public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/6] Use gdb::array_view some more, plug leaks
@ 2018-10-15 15:11 Pedro Alves
  2018-10-15 15:11 ` [PATCH 5/6] valops.c: Some more gdb::array_view Pedro Alves
                   ` (5 more replies)
  0 siblings, 6 replies; 20+ messages in thread
From: Pedro Alves @ 2018-10-15 15:11 UTC (permalink / raw)
  To: gdb-patches

This is the series that I had pointed Gary at in review of one of his
Coverity leak fixes:

  https://sourceware.org/ml/gdb-patches/2018-10/msg00258.html

It fixes that leak and the others I pointed at by converting
badness_vector to a std::vector.

I had originally written that std::vector patch as part of a series to
make more use of gdb::array_view.  I tried splitting it out of the
rest of the series, but quickly gave that up as it was messier than it
sounded, and was just pointless make work.  Instead, I've now rebased
the whole series, cleaned it up some more, wrote ChangeLogs, etc.  The
last patch is new too.

Pedro Alves (6):
  Use gdb:array_view in call_function_by_hand & friends
  invoke_xmethod & array_view
  Eliminate make_symbol_overload_list-related globals & cleanup
  C++ify badness_vector, fix leaks
  valops.c: Some more gdb::array_view
  valops.c: Overload resolution code: Rename parameters/locals

 gdb/ada-lang.c                       |   4 +-
 gdb/common/array-view.h              |  52 +++++
 gdb/compile/compile-object-run.c     |   4 +-
 gdb/cp-support.c                     | 142 +++++++-------
 gdb/cp-support.h                     |  13 +-
 gdb/elfread.c                        |   2 +-
 gdb/eval.c                           |  32 ++--
 gdb/extension.c                      |  12 +-
 gdb/extension.h                      |  32 ++--
 gdb/gcore.c                          |   2 +-
 gdb/gdbtypes.c                       |  50 +++--
 gdb/gdbtypes.h                       |  18 +-
 gdb/guile/scm-value.c                |   4 +-
 gdb/infcall.c                        |  29 +--
 gdb/infcall.h                        |   7 +-
 gdb/linux-fork.c                     |   7 +-
 gdb/linux-tdep.c                     |   4 +-
 gdb/objc-lang.c                      |  13 +-
 gdb/python/py-value.c                |   6 +-
 gdb/python/py-xmethods.c             |  40 ++--
 gdb/rust-lang.c                      |   2 +-
 gdb/unittests/array-view-selftests.c |  35 ++++
 gdb/valarith.c                       |  53 +++---
 gdb/valops.c                         | 355 ++++++++++++++++-------------------
 gdb/value.c                          |  13 +-
 gdb/value.h                          |   6 +-
 26 files changed, 484 insertions(+), 453 deletions(-)

-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 2/6] invoke_xmethod & array_view
  2018-10-15 15:11 [PATCH 0/6] Use gdb::array_view some more, plug leaks Pedro Alves
                   ` (2 preceding siblings ...)
  2018-10-15 15:11 ` [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends Pedro Alves
@ 2018-10-15 15:11 ` Pedro Alves
  2018-10-17 16:21   ` Simon Marchi
  2018-10-15 15:16 ` [PATCH 4/6] C++ify badness_vector, fix leaks Pedro Alves
  2018-10-15 15:18 ` [PATCH 6/6] valops.c: Overload resolution code: Rename parameters/locals Pedro Alves
  5 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2018-10-15 15:11 UTC (permalink / raw)
  To: gdb-patches

This replaces more pointer+length with gdb::array_view.  This time,
around invoke_xmethod, and then propagating the fallout around, which
inevitably leads to the overload resolution code.

There are several places in the code that want to grab a slice of an
array, by advanting the array pointer, and decreasing the length
pointer.  This patch introduces a pair of new
gdb::array_view::slice(...) methods to make that convenient and clear.
Unit test included.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* common/array-view.h (array_view::splice(size_type, size_t)): New.
	(array_view::splice(size_type)): New.
	* eval.c (eval_call, evaluate_funcall): Adjust to use array_view.
	* extension.c (xmethod_worker::get_arg_types): Adjust to return an
	std::vector.
	(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
	* extension.h: Include "common/array-view.h".
	(xmethod_worker::invoke): Adjust to use gdb::array_view.
	(xmethod_worker::get_arg_types): Adjust to return an std::vector.
	(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
	(xmethod_worker::do_get_arg_types): Adjust to use std::vector.
	(xmethod_worker::do_get_result_type): Adjust to use
	gdb::array_view.
	* gdbtypes.c (rank_function): Adjust to use gdb::array_view.
	* gdbtypes.h: Include "common/array-view.h".
	(rank_function): Adjust to use gdb::array_view.
	* python/py-xmethods.c (python_xmethod_worker::invoke)
	(python_xmethod_worker::do_get_arg_types)
	(python_xmethod_worker::do_get_result_type)
	(python_xmethod_worker::invoke): Adjust to new interfaces.
	* valarith.c (value_user_defined_cpp_op, value_user_defined_op)
	(value_x_binop, value_x_unop): Adjust to use gdb::array_view.
	* valops.c (find_overload_match, find_oload_champ_namespace)
	(find_oload_champ_namespace_loop, find_oload_champ): Adjust to use
	gdb:array_view and the new xmethod_worker interfaces.
	* value.c (result_type_of_xmethod, call_xmethod): Adjust to use
	gdb::array_view.
	* value.h (find_overload_match, result_type_of_xmethod)
	(call_xmethod): Adjust to use gdb::array_view.
	* unittests/array-view-selftests.c: Add slicing tests.
---
 gdb/common/array-view.h              |  11 ++++
 gdb/eval.c                           |  14 +++--
 gdb/extension.c                      |  12 ++--
 gdb/extension.h                      |  32 +++++------
 gdb/gdbtypes.c                       |  21 ++++---
 gdb/gdbtypes.h                       |   5 +-
 gdb/python/py-xmethods.c             |  40 ++++++--------
 gdb/unittests/array-view-selftests.c |  22 ++++++++
 gdb/valarith.c                       |  50 ++++++++---------
 gdb/valops.c                         | 104 +++++++++++++++++------------------
 gdb/value.c                          |  13 ++---
 gdb/value.h                          |   6 +-
 12 files changed, 179 insertions(+), 151 deletions(-)

diff --git a/gdb/common/array-view.h b/gdb/common/array-view.h
index 45d1a4720e..679d2e95c7 100644
--- a/gdb/common/array-view.h
+++ b/gdb/common/array-view.h
@@ -169,6 +169,17 @@ public:
   constexpr size_type size () const noexcept { return m_size; }
   constexpr bool empty () const noexcept { return m_size == 0; }
 
+  /* Slice an array view.  */
+
+  /* Return a new array view over SIZE elements starting at START.  */
+  constexpr array_view<T> slice (size_type start, size_t size) const noexcept
+  { return {m_array + start, size}; }
+
+  /* Return a new array view over all the elements after START,
+     inclusive.  */
+  constexpr array_view<T> slice (size_type start) const noexcept
+  { return {m_array + start, size () - start}; }
+
 private:
   T *m_array;
   size_type m_size;
diff --git a/gdb/eval.c b/gdb/eval.c
index 255d51b0a2..23e5f76a54 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -789,7 +789,9 @@ eval_call (expression *exp, enum noside noside,
       else if (TYPE_CODE (ftype) == TYPE_CODE_XMETHOD)
 	{
 	  type *return_type
-	    = result_type_of_xmethod (argvec[0], nargs, argvec + 1);
+	    = result_type_of_xmethod (argvec[0],
+				      gdb::make_array_view (argvec + 1,
+							    nargs));
 
 	  if (return_type == NULL)
 	    error (_("Xmethod is missing return type."));
@@ -827,7 +829,7 @@ eval_call (expression *exp, enum noside noside,
       return call_internal_function (exp->gdbarch, exp->language_defn,
 				     argvec[0], nargs, argvec + 1);
     case TYPE_CODE_XMETHOD:
-      return call_xmethod (argvec[0], nargs, argvec + 1);
+      return call_xmethod (argvec[0], gdb::make_array_view (argvec + 1, nargs));
     default:
       return call_function_by_hand (argvec[0], default_return_type,
 				    gdb::make_array_view (argvec + 1, nargs));
@@ -1100,7 +1102,8 @@ evaluate_funcall (type *expect_type, expression *exp, int *pos,
       func_name = (char *) alloca (name_len + 1);
       strcpy (func_name, &exp->elts[string_pc + 1].string);
 
-      find_overload_match (&argvec[1], nargs, func_name,
+      find_overload_match (gdb::make_array_view (&argvec[1], nargs),
+			   func_name,
 			   NON_METHOD, /* not method */
 			   NULL, NULL, /* pass NULL symbol since
 					  symbol is unknown */
@@ -1136,7 +1139,8 @@ evaluate_funcall (type *expect_type, expression *exp, int *pos,
 	     evaluation.  */
 	  struct value *valp = NULL;
 
-	  (void) find_overload_match (&argvec[1], nargs, tstr,
+	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
+				      tstr,
 				      METHOD, /* method */
 				      &arg2,  /* the object */
 				      NULL, &valp, NULL,
@@ -1207,7 +1211,7 @@ evaluate_funcall (type *expect_type, expression *exp, int *pos,
 	  if (op == OP_VAR_VALUE)
 	    function = exp->elts[save_pos1+2].symbol;
 
-	  (void) find_overload_match (&argvec[1], nargs,
+	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
 				      NULL,        /* no need for name */
 				      NON_METHOD,  /* not method */
 				      NULL, function, /* the function */
diff --git a/gdb/extension.c b/gdb/extension.c
index e5c014667a..ca303a1a41 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -870,12 +870,12 @@ get_matching_xmethod_workers (struct type *type, const char *method_name,
 
 /* See extension.h.  */
 
-type **
-xmethod_worker::get_arg_types (int *nargs)
+std::vector<type *>
+xmethod_worker::get_arg_types ()
 {
-  type **type_array = NULL;
+  std::vector<type *> type_array;
 
-  ext_lang_rc rc = do_get_arg_types (nargs, &type_array);
+  ext_lang_rc rc = do_get_arg_types (type_array);
   if (rc == EXT_LANG_RC_ERROR)
     error (_("Error while looking for arg types of a xmethod worker "
 	     "defined in %s."), m_extlang->capitalized_name);
@@ -886,11 +886,11 @@ xmethod_worker::get_arg_types (int *nargs)
 /* See extension.h.  */
 
 struct type *
-xmethod_worker::get_result_type (value *object, value **args, int nargs)
+xmethod_worker::get_result_type (value *object, gdb::array_view<value *> args)
 {
   type *result_type;
 
-  ext_lang_rc rc = do_get_result_type (object, args, nargs, &result_type);
+  ext_lang_rc rc = do_get_result_type (object, args, &result_type);
   if (rc == EXT_LANG_RC_ERROR)
     {
       error (_("Error while fetching result type of an xmethod worker "
diff --git a/gdb/extension.h b/gdb/extension.h
index 0c8c4ee934..4716d6f360 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -22,6 +22,7 @@
 
 #include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc.  */
 #include "common/vec.h"
+#include "common/array-view.h"
 
 struct breakpoint;
 struct command_line;
@@ -186,38 +187,35 @@ struct xmethod_worker
   virtual ~xmethod_worker () = default;
 
   /* Invoke the xmethod encapsulated in this worker and return the result.
-     The method is invoked on OBJ with arguments in the ARGS array.  NARGS is
-     the length of the this array.  */
+     The method is invoked on OBJ with arguments in the ARGS array.  */
 
-  virtual value *invoke (value *obj, value **args, int nargs) = 0;
+  virtual value *invoke (value *obj, gdb::array_view<value *> args) = 0;
 
   /* Return the arg types of the xmethod encapsulated in this worker.
-     An array of arg types is returned.  The length of the array is returned in
-     NARGS.  The type of the 'this' object is returned as the first element of
-     array.  */
+     The type of the 'this' object is returned as the first element of
+     the vector.  */
 
-  type **get_arg_types (int *nargs);
+  std::vector<type *> get_arg_types ();
 
   /* Return the type of the result of the xmethod encapsulated in this worker.
-     OBJECT, ARGS, NARGS are the same as for invoke.  */
+     OBJECT and ARGS are the same as for invoke.  */
 
-  type *get_result_type (value *object, value **args, int nargs);
+  type *get_result_type (value *object, gdb::array_view<value *> args);
 
 private:
 
-  /* Return the types of the arguments the method takes.  The number of
-     arguments is returned in NARGS, and their types are returned in the array
-     ARGTYPES.  */
+  /* Return the types of the arguments the method takes.  The types
+     are returned in TYPE_ARGS, one per argument.  */
 
   virtual enum ext_lang_rc do_get_arg_types
-    (int *nargs, struct type ***arg_types) = 0;
+    (std::vector<type *> &type_args) = 0;
 
-  /* Fetch the type of the result of the method implemented by this worker.
-     OBJECT, ARGS, NARGS are the same as for the invoked method.  The result
-     type is stored in *RESULT_TYPE.  */
+  /* Fetch the type of the result of the method implemented by this
+     worker.  OBJECT and ARGS are the same as for the invoked method.
+     The result type is stored in *RESULT_TYPE.  */
 
   virtual enum ext_lang_rc do_get_result_type
-    (struct value *obj, struct value **args, int nargs,
+    (struct value *obj, gdb::array_view<value *> args,
      struct type **result_type_ptr) = 0;
 
   /* The language the xmethod worker is implemented in.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 9e87b8f4c5..4160d996de 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3464,21 +3464,20 @@ compare_badness (struct badness_vector *a, struct badness_vector *b)
     }
 }
 
-/* Rank a function by comparing its parameter types (PARMS, length
-   NPARMS), to the types of an argument list (ARGS, length NARGS).
-   Return a pointer to a badness vector.  This has NARGS + 1
-   entries.  */
+/* Rank a function by comparing its parameter types (PARMS), to the
+   types of an argument list (ARGS).  Return a pointer to a badness
+   vector.  This has ARGS.size() + 1 entries.  */
 
 struct badness_vector *
-rank_function (struct type **parms, int nparms, 
-	       struct value **args, int nargs)
+rank_function (gdb::array_view<type *> parms,
+	       gdb::array_view<value *> args)
 {
   int i;
   struct badness_vector *bv = XNEW (struct badness_vector);
-  int min_len = nparms < nargs ? nparms : nargs;
+  size_t min_len = std::min (parms.size (), args.size ());
 
-  bv->length = nargs + 1;	/* add 1 for the length-match rank.  */
-  bv->rank = XNEWVEC (struct rank, nargs + 1);
+  bv->length = args.size () + 1;	/* add 1 for the length-match rank.  */
+  bv->rank = XNEWVEC (struct rank, args.size () + 1);
 
   /* First compare the lengths of the supplied lists.
      If there is a mismatch, set it to a high value.  */
@@ -3487,7 +3486,7 @@ rank_function (struct type **parms, int nparms,
      arguments and ellipsis parameter lists, we should consider those
      and rank the length-match more finely.  */
 
-  LENGTH_MATCH (bv) = (nargs != nparms)
+  LENGTH_MATCH (bv) = (args.size () != parms.size ())
 		      ? LENGTH_MISMATCH_BADNESS
 		      : EXACT_MATCH_BADNESS;
 
@@ -3497,7 +3496,7 @@ rank_function (struct type **parms, int nparms,
 				 args[i - 1]);
 
   /* If more arguments than parameters, add dummy entries.  */
-  for (i = min_len + 1; i <= nargs; i++)
+  for (i = min_len + 1; i <= args.size (); i++)
     bv->rank[i] = TOO_FEW_PARAMS_BADNESS;
 
   return bv;
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index a115857c0a..731b18d082 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -45,6 +45,7 @@
  */
 
 #include "hashtab.h"
+#include "common/array-view.h"
 #include "common/offset-type.h"
 #include "common/enum-flags.h"
 #include "common/underlying.h"
@@ -2044,8 +2045,8 @@ extern int compare_ranks (struct rank a, struct rank b);
 
 extern int compare_badness (struct badness_vector *, struct badness_vector *);
 
-extern struct badness_vector *rank_function (struct type **, int,
-					     struct value **, int);
+extern struct badness_vector *rank_function (gdb::array_view<type *> parms,
+					     gdb::array_view<value *> args);
 
 extern struct rank rank_one_type (struct type *, struct type *,
 				  struct value *);
diff --git a/gdb/python/py-xmethods.c b/gdb/python/py-xmethods.c
index 8e616cd4e2..d871d95654 100644
--- a/gdb/python/py-xmethods.c
+++ b/gdb/python/py-xmethods.c
@@ -46,11 +46,11 @@ struct python_xmethod_worker : xmethod_worker
 
   /* Implementation of xmethod_worker::invoke for Python.  */
 
-  value *invoke (value *obj, value **args, int nargs) override;
+  value *invoke (value *obj, gdb::array_view<value *> args) override;
 
   /* Implementation of xmethod_worker::do_get_arg_types for Python.  */
 
-  ext_lang_rc do_get_arg_types (int *nargs, type ***arg_types) override;
+  ext_lang_rc do_get_arg_types (std::vector<type *> &type_args) override;
 
   /* Implementation of xmethod_worker::do_get_result_type for Python.
 
@@ -58,7 +58,7 @@ struct python_xmethod_worker : xmethod_worker
      result type, if the get_result_type operation is not provided by WORKER
      then EXT_LANG_RC_OK is returned and NULL is returned in *RESULT_TYPE.  */
 
-  ext_lang_rc do_get_result_type (value *obj, value **args, int nargs,
+  ext_lang_rc do_get_result_type (value *obj, gdb::array_view<value *> args,
 				  type **result_type_ptr) override;
 
 private:
@@ -293,7 +293,7 @@ gdbpy_get_matching_xmethod_workers
 /* See declaration.  */
 
 ext_lang_rc
-python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
+python_xmethod_worker::do_get_arg_types (std::vector<type *> &arg_types)
 {
   /* The gdbpy_enter object needs to be placed first, so that it's the last to
      be destroyed.  */
@@ -302,10 +302,6 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
   int i = 1, arg_count;
   gdbpy_ref<> list_iter;
 
-  /* Set nargs to -1 so that any premature return from this function returns
-     an invalid/unusable number of arg types.  */
-  *nargs = -1;
-
   gdbpy_ref<> get_arg_types_method
     (PyObject_GetAttrString (m_py_worker, get_arg_types_method_name));
   if (get_arg_types_method == NULL)
@@ -345,8 +341,7 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
     arg_count = 1;
 
   /* Include the 'this' argument in the size.  */
-  gdb::unique_xmalloc_ptr<struct type *> type_array
-    (XCNEWVEC (struct type *, arg_count + 1));
+  arg_types.resize (arg_count + 1);
   i = 1;
   if (list_iter != NULL)
     {
@@ -373,7 +368,7 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
 	      return EXT_LANG_RC_ERROR;
 	    }
 
-	  (type_array.get ())[i] = arg_type;
+	  arg_types[i] = arg_type;
 	  i++;
 	}
     }
@@ -393,7 +388,7 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
 	}
       else
 	{
-	  (type_array.get ())[i] = arg_type;
+	  arg_types[i] = arg_type;
 	  i++;
 	}
     }
@@ -402,10 +397,8 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
      be a 'const' value.  Hence, create a 'const' variant of the 'this' pointer
      type.  */
   obj_type = type_object_to_type (m_this_type);
-  (type_array.get ())[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type),
-					 NULL);
-  *nargs = i;
-  *arg_types = type_array.release ();
+  arg_types[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type),
+			       NULL);
 
   return EXT_LANG_RC_OK;
 }
@@ -413,7 +406,8 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
 /* See declaration.  */
 
 ext_lang_rc
-python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
+python_xmethod_worker::do_get_result_type (value *obj,
+					   gdb::array_view<value *> args,
 					   type **result_type_ptr)
 {
   struct type *obj_type, *this_type;
@@ -461,7 +455,7 @@ python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
       return EXT_LANG_RC_ERROR;
     }
 
-  gdbpy_ref<> py_arg_tuple (PyTuple_New (nargs + 1));
+  gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
   if (py_arg_tuple == NULL)
     {
       gdbpy_print_stack ();
@@ -472,7 +466,7 @@ python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
      release.  */
   PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
 
-  for (i = 0; i < nargs; i++)
+  for (i = 0; i < args.size (); i++)
     {
       PyObject *py_value_arg = value_to_value_object (args[i]);
 
@@ -508,8 +502,8 @@ python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
 /* See declaration.  */
 
 struct value *
-python_xmethod_worker::invoke (struct value *obj, struct value **args,
-			       int nargs)
+python_xmethod_worker::invoke (struct value *obj,
+			       gdb::array_view<value *> args)
 {
   gdbpy_enter enter_py (get_current_arch (), current_language);
 
@@ -546,7 +540,7 @@ python_xmethod_worker::invoke (struct value *obj, struct value **args,
       error (_("Error while executing Python code."));
     }
 
-  gdbpy_ref<> py_arg_tuple (PyTuple_New (nargs + 1));
+  gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
   if (py_arg_tuple == NULL)
     {
       gdbpy_print_stack ();
@@ -557,7 +551,7 @@ python_xmethod_worker::invoke (struct value *obj, struct value **args,
      release.  */
   PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
 
-  for (i = 0; i < nargs; i++)
+  for (i = 0; i < args.size (); i++)
     {
       PyObject *py_value_arg = value_to_value_object (args[i]);
 
diff --git a/gdb/unittests/array-view-selftests.c b/gdb/unittests/array-view-selftests.c
index 74defa1b40..746062c75a 100644
--- a/gdb/unittests/array-view-selftests.c
+++ b/gdb/unittests/array-view-selftests.c
@@ -496,6 +496,28 @@ run_tests ()
     for (size_t i = 0; i < len; i++)
       SELF_CHECK (view[i] == data[i]);
   }
+
+  /* Test slicing.  */
+  {
+    gdb_byte data[] = {0x55, 0x66, 0x77, 0x88, 0x99};
+    gdb::array_view<gdb_byte> view = data;
+
+    {
+      auto slc = view.slice (1, 3);
+      SELF_CHECK (slc.data () == data + 1);
+      SELF_CHECK (slc.size () == 3);
+      SELF_CHECK (slc[0] == data[1]);
+      SELF_CHECK (slc[0] == view[1]);
+    }
+
+    {
+      auto slc = view.slice (2);
+      SELF_CHECK (slc.data () == data + 2);
+      SELF_CHECK (slc.size () == 3);
+      SELF_CHECK (slc[0] == view[2]);
+      SELF_CHECK (slc[0] == data[2]);
+    }
+  }
 }
 
 } /* namespace array_view_tests */
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 875f5477c2..1e7a3727d5 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -281,14 +281,14 @@ unop_user_defined_p (enum exp_opcode op, struct value *arg1)
    situations or combinations thereof.  */
 
 static struct value *
-value_user_defined_cpp_op (struct value **args, int nargs, char *oper,
+value_user_defined_cpp_op (gdb::array_view<value *> args, char *oper,
                            int *static_memfuncp, enum noside noside)
 {
 
   struct symbol *symp = NULL;
   struct value *valp = NULL;
 
-  find_overload_match (args, nargs, oper, BOTH /* could be method */,
+  find_overload_match (args, oper, BOTH /* could be method */,
                        &args[0] /* objp */,
                        NULL /* pass NULL symbol since symbol is unknown */,
                        &valp, &symp, static_memfuncp, 0, noside);
@@ -312,19 +312,19 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *oper,
    function, otherwise return NULL.  */
 
 static struct value *
-value_user_defined_op (struct value **argp, struct value **args, char *name,
-                       int *static_memfuncp, int nargs, enum noside noside)
+value_user_defined_op (struct value **argp, gdb::array_view<value *> args, char *name,
+		       int *static_memfuncp, enum noside noside)
 {
   struct value *result = NULL;
 
   if (current_language->la_language == language_cplus)
     {
-      result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp,
+      result = value_user_defined_cpp_op (args, name, static_memfuncp,
 					  noside);
     }
   else
-    result = value_struct_elt (argp, args, name, static_memfuncp,
-                               "structure");
+    result = value_struct_elt (argp, args.data (), name, static_memfuncp,
+			       "structure");
 
   return result;
 }
@@ -342,7 +342,6 @@ struct value *
 value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	       enum exp_opcode otherop, enum noside noside)
 {
-  struct value **argvec;
   char *ptr;
   char tstr[13];
   int static_memfuncp;
@@ -356,10 +355,11 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
   if (TYPE_CODE (check_typedef (value_type (arg1))) != TYPE_CODE_STRUCT)
     error (_("Can't do that binary op on that type"));	/* FIXME be explicit */
 
-  argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+  value *argvec_storage[3];
+  gdb::array_view<value *> argvec = argvec_storage;
+
   argvec[1] = value_addr (arg1);
   argvec[2] = arg2;
-  argvec[3] = 0;
 
   /* Make the right function name up.  */
   strcpy (tstr, "operator__");
@@ -469,15 +469,15 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
       error (_("Invalid binary operation specified."));
     }
 
-  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
-                                     &static_memfuncp, 2, noside);
+  argvec[0] = value_user_defined_op (&arg1, argvec.slice (1), tstr,
+				     &static_memfuncp, noside);
 
   if (argvec[0])
     {
       if (static_memfuncp)
 	{
 	  argvec[1] = argvec[0];
-	  argvec++;
+	  argvec = argvec.slice (1);
 	}
       if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_XMETHOD)
 	{
@@ -486,13 +486,13 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	    {
 	      struct type *return_type
-		= result_type_of_xmethod (argvec[0], 2, argvec + 1);
+		= result_type_of_xmethod (argvec[0], argvec.slice (1));
 
 	      if (return_type == NULL)
 		error (_("Xmethod is missing return type."));
 	      return value_zero (return_type, VALUE_LVAL (arg1));
 	    }
-	  return call_xmethod (argvec[0], 2, argvec + 1);
+	  return call_xmethod (argvec[0], argvec.slice (1));
 	}
       if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	{
@@ -503,7 +503,7 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
       return call_function_by_hand (argvec[0], NULL,
-				    {argvec + 1, 2u - static_memfuncp});
+				    argvec.slice (1, 2 - static_memfuncp));
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
@@ -519,7 +519,6 @@ struct value *
 value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 {
   struct gdbarch *gdbarch = get_type_arch (value_type (arg1));
-  struct value **argvec;
   char *ptr;
   char tstr[13], mangle_tstr[13];
   int static_memfuncp, nargs;
@@ -532,7 +531,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
   if (TYPE_CODE (check_typedef (value_type (arg1))) != TYPE_CODE_STRUCT)
     error (_("Can't do that unary op on that type"));	/* FIXME be explicit */
 
-  argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+  value *argvec_storage[3];
+  gdb::array_view<value *> argvec = argvec_storage;
+
   argvec[1] = value_addr (arg1);
   argvec[2] = 0;
 
@@ -584,16 +585,15 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
       error (_("Invalid unary operation specified."));
     }
 
-  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
-                                     &static_memfuncp, nargs, noside);
+  argvec[0] = value_user_defined_op (&arg1, argvec.slice (1, nargs), tstr,
+				     &static_memfuncp, noside);
 
   if (argvec[0])
     {
       if (static_memfuncp)
 	{
 	  argvec[1] = argvec[0];
-	  nargs --;
-	  argvec++;
+	  argvec = argvec.slice (1);
 	}
       if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_XMETHOD)
 	{
@@ -602,13 +602,13 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	    {
 	      struct type *return_type
-		= result_type_of_xmethod (argvec[0], 1, argvec + 1);
+		= result_type_of_xmethod (argvec[0], argvec[1]);
 
 	      if (return_type == NULL)
 		error (_("Xmethod is missing return type."));
 	      return value_zero (return_type, VALUE_LVAL (arg1));
 	    }
-	  return call_xmethod (argvec[0], 1, argvec + 1);
+	  return call_xmethod (argvec[0], argvec[1]);
 	}
       if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	{
@@ -619,7 +619,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
       return call_function_by_hand (argvec[0], NULL,
-				    gdb::make_array_view (argvec + 1, nargs));
+				    argvec.slice (1, nargs));
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
diff --git a/gdb/valops.c b/gdb/valops.c
index 4758b5cdfc..f0e53a7ce9 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -54,20 +54,19 @@ static struct value *search_struct_method (const char *, struct value **,
 					   struct value **,
 					   LONGEST, int *, struct type *);
 
-static int find_oload_champ_namespace (struct value **, int,
+static int find_oload_champ_namespace (gdb::array_view<value *> args,
 				       const char *, const char *,
 				       struct symbol ***,
 				       struct badness_vector **,
 				       const int no_adl);
 
-static
-int find_oload_champ_namespace_loop (struct value **, int,
-				     const char *, const char *,
-				     int, struct symbol ***,
-				     struct badness_vector **, int *,
-				     const int no_adl);
+static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
+					    const char *, const char *,
+					    int, struct symbol ***,
+					    struct badness_vector **, int *,
+					    const int no_adl);
 
-static int find_oload_champ (struct value **, int, int,
+static int find_oload_champ (gdb::array_view<value *> args, int,
 			     struct fn_field *,
 			     const std::vector<xmethod_worker_up> *,
 			     struct symbol **, struct badness_vector **);
@@ -2446,11 +2445,11 @@ value_find_oload_method_list (struct value **argp, const char *method,
 		    basetype, boffset);
 }
 
-/* Given an array of arguments (ARGS) (which includes an
-   entry for "this" in the case of C++ methods), the number of
-   arguments NARGS, the NAME of a function, and whether it's a method or
-   not (METHOD), find the best function that matches on the argument types
-   according to the overload resolution rules.
+/* Given an array of arguments (ARGS) (which includes an entry for
+   "this" in the case of C++ methods), the NAME of a function, and
+   whether it's a method or not (METHOD), find the best function that
+   matches on the argument types according to the overload resolution
+   rules.
 
    METHOD can be one of three values:
      NON_METHOD for non-member functions.
@@ -2493,7 +2492,7 @@ value_find_oload_method_list (struct value **argp, const char *method,
    resolution is permitted.  */
 
 int
-find_overload_match (struct value **args, int nargs,
+find_overload_match (gdb::array_view<value *> args,
 		     const char *name, enum oload_search_type method,
 		     struct value **objp, struct symbol *fsym,
 		     struct value **valp, struct symbol **symp, 
@@ -2578,12 +2577,12 @@ find_overload_match (struct value **args, int nargs,
 	{
 	  gdb_assert (TYPE_SELF_TYPE (fns_ptr[0].type) != NULL);
 
-	  src_method_oload_champ = find_oload_champ (args, nargs,
+	  src_method_oload_champ = find_oload_champ (args,
 						     num_fns, fns_ptr, NULL,
 						     NULL, &src_method_badness);
 
 	  src_method_match_quality = classify_oload_match
-	    (src_method_badness, nargs,
+	    (src_method_badness, args.size (),
 	     oload_method_static_p (fns_ptr, src_method_oload_champ));
 
 	  make_cleanup (xfree, src_method_badness);
@@ -2591,11 +2590,10 @@ find_overload_match (struct value **args, int nargs,
 
       if (!xm_worker_vec.empty ())
 	{
-	  ext_method_oload_champ = find_oload_champ (args, nargs,
-						     0, NULL, &xm_worker_vec,
+	  ext_method_oload_champ = find_oload_champ (args, 0, NULL, &xm_worker_vec,
 						     NULL, &ext_method_badness);
 	  ext_method_match_quality = classify_oload_match (ext_method_badness,
-							   nargs, 0);
+							   args.size (), 0);
 	  make_cleanup (xfree, ext_method_badness);
 	}
 
@@ -2708,7 +2706,7 @@ find_overload_match (struct value **args, int nargs,
           return 0;
         }
 
-      func_oload_champ = find_oload_champ_namespace (args, nargs,
+      func_oload_champ = find_oload_champ_namespace (args,
                                                      func_name,
                                                      qualified_name,
                                                      &oload_syms,
@@ -2716,7 +2714,8 @@ find_overload_match (struct value **args, int nargs,
                                                      no_adl);
 
       if (func_oload_champ >= 0)
-	func_match_quality = classify_oload_match (func_badness, nargs, 0);
+	func_match_quality = classify_oload_match (func_badness,
+						   args.size (), 0);
 
       make_cleanup (xfree, oload_syms);
       make_cleanup (xfree, func_badness);
@@ -2855,7 +2854,7 @@ find_overload_match (struct value **args, int nargs,
    performned.  */
 
 static int
-find_oload_champ_namespace (struct value **args, int nargs,
+find_oload_champ_namespace (gdb::array_view<value *> args,
 			    const char *func_name,
 			    const char *qualified_name,
 			    struct symbol ***oload_syms,
@@ -2864,7 +2863,7 @@ find_oload_champ_namespace (struct value **args, int nargs,
 {
   int oload_champ;
 
-  find_oload_champ_namespace_loop (args, nargs,
+  find_oload_champ_namespace_loop (args,
 				   func_name,
 				   qualified_name, 0,
 				   oload_syms, oload_champ_bv,
@@ -2884,7 +2883,7 @@ find_oload_champ_namespace (struct value **args, int nargs,
    *OLOAD_CHAMP_BV.  */
 
 static int
-find_oload_champ_namespace_loop (struct value **args, int nargs,
+find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				 const char *func_name,
 				 const char *qualified_name,
 				 int namespace_len,
@@ -2921,7 +2920,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
     {
       searched_deeper = 1;
 
-      if (find_oload_champ_namespace_loop (args, nargs,
+      if (find_oload_champ_namespace_loop (args,
 					   func_name, qualified_name,
 					   next_namespace_len,
 					   oload_syms, oload_champ_bv,
@@ -2956,16 +2955,16 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
 
       /* Prepare list of argument types for overload resolution.  */
       arg_types = (struct type **)
-	alloca (nargs * (sizeof (struct type *)));
-      for (ix = 0; ix < nargs; ix++)
+	alloca (args.size () * (sizeof (struct type *)));
+      for (ix = 0; ix < args.size (); ix++)
 	arg_types[ix] = value_type (args[ix]);
-      make_symbol_overload_list_adl (arg_types, nargs, func_name);
+      make_symbol_overload_list_adl (arg_types, args.size (), func_name);
     }
 
   while (new_oload_syms[num_fns])
     ++num_fns;
 
-  new_oload_champ = find_oload_champ (args, nargs, num_fns,
+  new_oload_champ = find_oload_champ (args, num_fns,
 				      NULL, NULL, new_oload_syms,
 				      &new_oload_champ_bv);
 
@@ -2977,7 +2976,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
      it's a bad match.  */
 
   if (new_oload_champ != -1
-      && classify_oload_match (new_oload_champ_bv, nargs, 0) == STANDARD)
+      && classify_oload_match (new_oload_champ_bv, args.size (), 0) == STANDARD)
     {
       *oload_syms = new_oload_syms;
       *oload_champ = new_oload_champ;
@@ -3002,11 +3001,10 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
     }
 }
 
-/* Look for a function to take NARGS args of ARGS.  Find
-   the best match from among the overloaded methods or functions
-   given by FNS_PTR or OLOAD_SYMS or XM_WORKER_VEC, respectively.
-   One, and only one of FNS_PTR, OLOAD_SYMS and XM_WORKER_VEC can be
-   non-NULL.
+/* Look for a function to take ARGS.  Find the best match from among
+   the overloaded methods or functions given by FNS_PTR or OLOAD_SYMS
+   or XM_WORKER_VEC, respectively.  One, and only one of FNS_PTR,
+   OLOAD_SYMS and XM_WORKER_VEC can be non-NULL.
 
    If XM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
    or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
@@ -3017,7 +3015,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
    It is the caller's responsibility to free *OLOAD_CHAMP_BV.  */
 
 static int
-find_oload_champ (struct value **args, int nargs,
+find_oload_champ (gdb::array_view<value *> args,
 		  int num_fns, struct fn_field *fns_ptr,
 		  const std::vector<xmethod_worker_up> *xm_worker_vec,
 		  struct symbol **oload_syms,
@@ -3047,16 +3045,17 @@ find_oload_champ (struct value **args, int nargs,
     {
       int jj;
       int static_offset = 0;
-      int nparms;
-      struct type **parm_types;
+      std::vector<type *> parm_types;
 
       if (xm_worker_vec != NULL)
 	{
 	  xmethod_worker *worker = (*xm_worker_vec)[ix].get ();
-	  parm_types = worker->get_arg_types (&nparms);
+	  parm_types = worker->get_arg_types ();
 	}
       else
 	{
+	  size_t nparms;
+
 	  if (fns_ptr != NULL)
 	    {
 	      nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
@@ -3065,19 +3064,21 @@ find_oload_champ (struct value **args, int nargs,
 	  else
 	    nparms = TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
 
-	  parm_types = XNEWVEC (struct type *, nparms);
+	  parm_types.reserve (nparms);
 	  for (jj = 0; jj < nparms; jj++)
-	    parm_types[jj] = (fns_ptr != NULL
-			      ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
-			      : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
-						 jj));
+	    {
+	      type *t = (fns_ptr != NULL
+			 ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
+			 : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
+					    jj));
+	      parm_types.push_back (t);
+	    }
 	}
 
       /* Compare parameter types to supplied argument types.  Skip
          THIS for static methods.  */
-      bv = rank_function (parm_types, nparms, 
-			  args + static_offset,
-			  nargs - static_offset);
+      bv = rank_function (parm_types,
+			  args.slice (static_offset));
 
       if (!*oload_champ_bv)
 	{
@@ -3103,24 +3104,23 @@ find_oload_champ (struct value **args, int nargs,
 	  default:
 	    break;
 	  }
-      xfree (parm_types);
       if (overload_debug)
 	{
 	  if (fns_ptr != NULL)
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded method instance %s, # of parms %d\n",
-			      fns_ptr[ix].physname, nparms);
+			      fns_ptr[ix].physname, (int) parm_types.size ());
 	  else if (xm_worker_vec != NULL)
 	    fprintf_filtered (gdb_stderr,
 			      "Xmethod worker, # of parms %d\n",
-			      nparms);
+			      (int) parm_types.size ());
 	  else
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded function instance "
 			      "%s # of parms %d\n",
 			      SYMBOL_DEMANGLED_NAME (oload_syms[ix]), 
-			      nparms);
-	  for (jj = 0; jj < nargs - static_offset; jj++)
+			      (int) parm_types.size ());
+	  for (jj = 0; jj < args.size () - static_offset; jj++)
 	    fprintf_filtered (gdb_stderr,
 			      "...Badness @ %d : %d\n", 
 			      jj, bv->rank[jj].rank);
diff --git a/gdb/value.c b/gdb/value.c
index 38fc18e0f6..c7b8468b39 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2583,24 +2583,23 @@ value_from_xmethod (xmethod_worker_up &&worker)
 /* Return the type of the result of TYPE_CODE_XMETHOD value METHOD.  */
 
 struct type *
-result_type_of_xmethod (struct value *method, int argc, struct value **argv)
+result_type_of_xmethod (struct value *method, gdb::array_view<value *> argv)
 {
   gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
-	      && method->lval == lval_xcallable && argc > 0);
+	      && method->lval == lval_xcallable && !argv.empty ());
 
-  return method->location.xm_worker->get_result_type
-    (argv[0], argv + 1, argc - 1);
+  return method->location.xm_worker->get_result_type (argv[0], argv.slice (1));
 }
 
 /* Call the xmethod corresponding to the TYPE_CODE_XMETHOD value METHOD.  */
 
 struct value *
-call_xmethod (struct value *method, int argc, struct value **argv)
+call_xmethod (struct value *method, gdb::array_view<value *> argv)
 {
   gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
-	      && method->lval == lval_xcallable && argc > 0);
+	      && method->lval == lval_xcallable && !argv.empty ());
 
-  return method->location.xm_worker->invoke (argv[0], argv + 1, argc - 1);
+  return method->location.xm_worker->invoke (argv[0], argv.slice (1));
 }
 \f
 /* Extract a value as a C number (either long or double).
diff --git a/gdb/value.h b/gdb/value.h
index 4d75c966ed..54caa58e7f 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -835,7 +835,7 @@ extern struct value *value_static_field (struct type *type, int fieldno);
 
 enum oload_search_type { NON_METHOD, METHOD, BOTH };
 
-extern int find_overload_match (struct value **args, int nargs,
+extern int find_overload_match (gdb::array_view<value *> args,
 				const char *name,
 				enum oload_search_type method,
 				struct value **objp, struct symbol *fsym,
@@ -1175,10 +1175,10 @@ char *value_internal_function_name (struct value *);
 extern struct value *value_from_xmethod (xmethod_worker_up &&worker);
 
 extern struct type *result_type_of_xmethod (struct value *method,
-					    int argc, struct value **argv);
+					    gdb::array_view<value *> argv);
 
 extern struct value *call_xmethod (struct value *method,
-				   int argc, struct value **argv);
+				   gdb::array_view<value *> argv);
 
 /* Given a discriminated union type and some corresponding value
    contents, this will return the field index of the currently active
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 5/6] valops.c: Some more gdb::array_view
  2018-10-15 15:11 [PATCH 0/6] Use gdb::array_view some more, plug leaks Pedro Alves
@ 2018-10-15 15:11 ` Pedro Alves
  2018-10-17 18:03   ` Simon Marchi
  2018-10-15 15:11 ` [PATCH 3/6] Eliminate make_symbol_overload_list-related globals & cleanup Pedro Alves
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2018-10-15 15:11 UTC (permalink / raw)
  To: gdb-patches

This commit replaces some more use of pointer+length pairs in the
overload resolution code with gdb::array_view.

find_oload_champ's interface is simplified/normalized: the xmethods
parameter is converted from std::vector to array pointer, and then the
num_fns parameter is always passed in, no matter the array which is
non-NULL.  I tweaked the formatting of callers a little bit here and
there so that the 3 optional parameters are all in the same line.  (I
tried making the 3 optional array parameters be array_views, but the
resulting code didn't look as nice.)

gdb/ChangeLog:
2018-10-14  Pedro Alves  <palves@redhat.com>

	* valops.c (find_method_list): Replace pointer and length
	parameters with an gdb::array_view.  Adjust.
	(value_find_oload_method_list): Likewise.
	(find_overload_match): Use gdb::array_view for methods list.
	Adjust to find_oload_champ interface change.
	(find_oload_champ): 'xm_worker_vec' parameter now a pointer/array.
	'num_fns' parameter now a size_t.  Eliminate 'fn_count' local.
---
 gdb/valops.c | 101 +++++++++++++++++++++++++++--------------------------------
 1 file changed, 47 insertions(+), 54 deletions(-)

diff --git a/gdb/valops.c b/gdb/valops.c
index 1cf3fd8fd5..ef2af09799 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -66,10 +66,12 @@ static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 					    badness_vector *, int *,
 					    const int no_adl);
 
-static int find_oload_champ (gdb::array_view<value *> args, int,
-			     struct fn_field *,
-			     const std::vector<xmethod_worker_up> *,
-			     struct symbol **, badness_vector *);
+static int find_oload_champ (gdb::array_view<value *> args,
+			     size_t num_fns,
+			     fn_field *fns_ptr,
+			     xmethod_worker_up *xm_worker_vec,
+			     symbol **oload_syms,
+			     badness_vector *oload_champ_bv);
 
 static int oload_method_static_p (struct fn_field *, int);
 
@@ -95,11 +97,6 @@ static CORE_ADDR allocate_space_in_inferior (int);
 
 static struct value *cast_into_complex (struct type *, struct value *);
 
-static void find_method_list (struct value **, const char *,
-			      LONGEST, struct type *, struct fn_field **, int *,
-			      std::vector<xmethod_worker_up> *,
-			      struct type **, LONGEST *);
-
 int overload_resolution = 0;
 static void
 show_overload_resolution (struct ui_file *file, int from_tty,
@@ -2292,7 +2289,7 @@ value_union_variant (struct type *union_type, const gdb_byte *contents)
 }
 
 /* Search through the methods of an object (and its bases) to find a
-   specified method.  Return the pointer to the fn_field list FN_LIST of
+   specified method.  Return a reference to the fn_field list FN_LIST of
    overloaded instances defined in the source language.  If available
    and matching, a vector of matching xmethods defined in extension
    languages are also returned in XM_WORKER_VEC
@@ -2316,7 +2313,7 @@ value_union_variant (struct type *union_type, const gdb_byte *contents)
 static void
 find_method_list (struct value **argp, const char *method,
 		  LONGEST offset, struct type *type,
-		  struct fn_field **fn_list, int *num_fns,
+		  gdb::array_view<fn_field> *fn_list,
 		  std::vector<xmethod_worker_up> *xm_worker_vec,
 		  struct type **basetype, LONGEST *boffset)
 {
@@ -2330,7 +2327,7 @@ find_method_list (struct value **argp, const char *method,
      This function is called recursively to search through base classes.
      If there is a source method match found at some stage, then we need not
      look for source methods in consequent recursive calls.  */
-  if ((*fn_list) == NULL)
+  if (fn_list->empty ())
     {
       for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
 	{
@@ -2341,9 +2338,8 @@ find_method_list (struct value **argp, const char *method,
 	    {
 	      int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
 	      f = TYPE_FN_FIELDLIST1 (type, i);
-	      *fn_list = f;
+	      *fn_list = gdb::make_array_view (f, len);
 
-	      *num_fns = len;
 	      *basetype = type;
 	      *boffset = offset;
 
@@ -2385,7 +2381,7 @@ find_method_list (struct value **argp, const char *method,
 	}
 
       find_method_list (argp, method, base_offset + offset,
-			TYPE_BASECLASS (type, i), fn_list, num_fns,
+			TYPE_BASECLASS (type, i), fn_list,
 			xm_worker_vec, basetype, boffset);
     }
 }
@@ -2398,9 +2394,8 @@ find_method_list (struct value **argp, const char *method,
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is the method name.
    OFFSET is the offset within the value contents.
-   FN_LIST is the pointer to matching overloaded instances defined in
+   FN_LIST is the list of matching overloaded instances defined in
       source language.
-   NUM_FNS is the number of overloaded instances.
    XM_WORKER_VEC is the vector of matching xmethod workers defined in
       extension languages.
    BASETYPE is set to the type of the base subobject that defines the
@@ -2409,8 +2404,8 @@ find_method_list (struct value **argp, const char *method,
 
 static void
 value_find_oload_method_list (struct value **argp, const char *method,
-                              LONGEST offset, struct fn_field **fn_list,
-                              int *num_fns,
+			      LONGEST offset,
+			      gdb::array_view<fn_field> *fn_list,
 			      std::vector<xmethod_worker_up> *xm_worker_vec,
 			      struct type **basetype, LONGEST *boffset)
 {
@@ -2436,11 +2431,10 @@ value_find_oload_method_list (struct value **argp, const char *method,
   gdb_assert (fn_list != NULL && xm_worker_vec != NULL);
 
   /* Clear the lists.  */
-  *fn_list = NULL;
-  *num_fns = 0;
+  *fn_list = {};
   xm_worker_vec->clear ();
 
-  find_method_list (argp, method, 0, t, fn_list, num_fns, xm_worker_vec,
+  find_method_list (argp, method, 0, t, fn_list, xm_worker_vec,
 		    basetype, boffset);
 }
 
@@ -2514,13 +2508,11 @@ find_overload_match (gdb::array_view<value *> args,
 
   struct value *temp = obj;
   /* For methods, the list of overloaded methods.  */
-  struct fn_field *fns_ptr = NULL;
+  gdb::array_view<fn_field> fns_list;
   /* For non-methods, the list of overloaded function symbols.  */
   std::vector<symbol *> oload_syms;
   /* For xmethods, the VEC of xmethod workers.  */
   std::vector<xmethod_worker_up> xm_worker_vec;
-  /* Number of overloaded instances being considered.  */
-  int num_fns = 0;
   struct type *basetype = NULL;
   LONGEST boffset;
 
@@ -2560,11 +2552,11 @@ find_overload_match (gdb::array_view<value *> args,
 	}
 
       /* Retrieve the list of methods with the name NAME.  */
-      value_find_oload_method_list (&temp, name, 0, &fns_ptr, &num_fns,
+      value_find_oload_method_list (&temp, name, 0, &fns_list,
 				    &xm_worker_vec, &basetype, &boffset);
       /* If this is a method only search, and no methods were found
          the search has failed.  */
-      if (method == METHOD && (!fns_ptr || !num_fns) && xm_worker_vec.empty ())
+      if (method == METHOD && fns_list.empty () && xm_worker_vec.empty ())
 	error (_("Couldn't find method %s%s%s"),
 	       obj_type_name,
 	       (obj_type_name && *obj_type_name) ? "::" : "",
@@ -2572,23 +2564,28 @@ find_overload_match (gdb::array_view<value *> args,
       /* If we are dealing with stub method types, they should have
 	 been resolved by find_method_list via
 	 value_find_oload_method_list above.  */
-      if (fns_ptr)
+      if (!fns_list.empty ())
 	{
-	  gdb_assert (TYPE_SELF_TYPE (fns_ptr[0].type) != NULL);
+	  gdb_assert (TYPE_SELF_TYPE (fns_list[0].type) != NULL);
 
-	  src_method_oload_champ = find_oload_champ (args,
-						     num_fns, fns_ptr, NULL,
-						     NULL, &src_method_badness);
+	  src_method_oload_champ
+	    = find_oload_champ (args,
+				fns_list.size (),
+				fns_list.data (), NULL, NULL,
+				&src_method_badness);
 
 	  src_method_match_quality = classify_oload_match
 	    (src_method_badness, args.size (),
-	     oload_method_static_p (fns_ptr, src_method_oload_champ));
+	     oload_method_static_p (fns_list.data (), src_method_oload_champ));
 	}
 
       if (!xm_worker_vec.empty ())
 	{
-	  ext_method_oload_champ = find_oload_champ (args, 0, NULL, &xm_worker_vec,
-						     NULL, &ext_method_badness);
+	  ext_method_oload_champ
+	    = find_oload_champ (args,
+				xm_worker_vec.size (),
+				NULL, xm_worker_vec.data (), NULL,
+				&ext_method_badness);
 	  ext_method_match_quality = classify_oload_match (ext_method_badness,
 							   args.size (), 0);
 	}
@@ -2787,22 +2784,22 @@ find_overload_match (gdb::array_view<value *> args,
     }
 
   if (staticp != NULL)
-    *staticp = oload_method_static_p (fns_ptr, method_oload_champ);
+    *staticp = oload_method_static_p (fns_list.data (), method_oload_champ);
 
   if (method_oload_champ >= 0)
     {
       if (src_method_oload_champ >= 0)
 	{
-	  if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ)
+	  if (TYPE_FN_FIELD_VIRTUAL_P (fns_list, method_oload_champ)
 	      && noside != EVAL_AVOID_SIDE_EFFECTS)
 	    {
-	      *valp = value_virtual_fn_field (&temp, fns_ptr,
+	      *valp = value_virtual_fn_field (&temp, fns_list.data (),
 					      method_oload_champ, basetype,
 					      boffset);
 	    }
 	  else
-	    *valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
-				    basetype, boffset);
+	    *valp = value_fn_field (&temp, fns_list.data (),
+				    method_oload_champ, basetype, boffset);
 	}
       else
 	*valp = value_from_xmethod
@@ -2947,7 +2944,8 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     }
 
   badness_vector new_oload_champ_bv;
-  new_oload_champ = find_oload_champ (args, new_oload_syms.size (),
+  new_oload_champ = find_oload_champ (args,
+				      new_oload_syms.size (),
 				      NULL, NULL, new_oload_syms.data (),
 				      &new_oload_champ_bv);
 
@@ -2984,20 +2982,20 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
    or XM_WORKER_VEC, respectively.  One, and only one of FNS_PTR,
    OLOAD_SYMS and XM_WORKER_VEC can be non-NULL.
 
-   If XM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
-   or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
+   NUM_FNS is the length of the array pointed at by FNS_PTR,
+   OLOAD_SYMS of XM_WORKER_VEC, whichever is non-NULL.
 
    Return the index of the best match; store an indication of the
    quality of the match in OLOAD_CHAMP_BV.  */
 
 static int
 find_oload_champ (gdb::array_view<value *> args,
-		  int num_fns, struct fn_field *fns_ptr,
-		  const std::vector<xmethod_worker_up> *xm_worker_vec,
-		  struct symbol **oload_syms,
+		  size_t num_fns,
+		  fn_field *fns_ptr,
+		  xmethod_worker_up *xm_worker_vec,
+		  symbol **oload_syms,
 		  badness_vector *oload_champ_bv)
 {
-  int ix;
   /* A measure of how good an overloaded instance is.  */
   badness_vector bv;
   /* Index of best overloaded function.  */
@@ -3012,20 +3010,15 @@ find_oload_champ (gdb::array_view<value *> args,
   gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) + (xm_worker_vec != NULL)
 	      == 1);
 
-  int fn_count = xm_worker_vec != NULL ? xm_worker_vec->size () : num_fns;
-
   /* Consider each candidate in turn.  */
-  for (ix = 0; ix < fn_count; ix++)
+  for (size_t ix = 0; ix < num_fns; ix++)
     {
       int jj;
       int static_offset = 0;
       std::vector<type *> parm_types;
 
       if (xm_worker_vec != NULL)
-	{
-	  xmethod_worker *worker = (*xm_worker_vec)[ix].get ();
-	  parm_types = worker->get_arg_types ();
-	}
+	parm_types = xm_worker_vec[ix]->get_arg_types ();
       else
 	{
 	  size_t nparms;
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 3/6] Eliminate make_symbol_overload_list-related globals & cleanup
  2018-10-15 15:11 [PATCH 0/6] Use gdb::array_view some more, plug leaks Pedro Alves
  2018-10-15 15:11 ` [PATCH 5/6] valops.c: Some more gdb::array_view Pedro Alves
@ 2018-10-15 15:11 ` Pedro Alves
  2018-10-17 17:25   ` Simon Marchi
  2018-10-15 15:11 ` [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends Pedro Alves
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2018-10-15 15:11 UTC (permalink / raw)
  To: gdb-patches

This gets rid of a few globals and a cleanup.

make_symbol_overload_list & friends currently maintain a global
open-coded vector.  Reimplement that with a std::vector, trickled down
through the functions.  Rename a few functions from "make_" to "add_"
for clarity.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cp-support.c (sym_return_val_size, sym_return_val_index)
	(sym_return_val): Delete.
	(overload_list_add_symbol): Add std::vector parameter.  Adjust to
	add to the vector.
	(make_symbol_overload_list): Adjust to return a std::vector
	instead of maintaining a global open coded vector.
	(make_symbol_overload_list_block): Add std::vector parameter.
	(make_symbol_overload_list_block): Rename to ...
	(add_symbol_overload_list_block): ... this and add std::vector
	parameter.
	(make_symbol_overload_list_namespace): Rename to ...
	(add_symbol_overload_list_namespace): ... this and add std::vector
	parameter.
	(make_symbol_overload_list_adl_namespace): Rename to ...
	(add_symbol_overload_list_adl_namespace): ... this and add
	std::vector parameter.
	(make_symbol_overload_list_adl): Delete.
	(add_symbol_overload_list_adl): New.
	(make_symbol_overload_list_using): Rename to ...
	(add_symbol_overload_list_using): ... this and add std::vector
	parameter.
	(make_symbol_overload_list_qualified): Rename to ...
	(add_symbol_overload_list_qualified): ... this and add std::vector
	parameter.
	* cp-support.h: Include "common/array-view.h" and <vector>.
	(make_symbol_overload_list): Change return type to std::vector.
	(make_symbol_overload_list_adl): Delete declaration.
	(add_symbol_overload_list_adl): New declaration.
	* valops.c (find_overload_match): Local 'oload_syms' now a
	std::vector.
	(find_oload_champ_namespace): 'oload_syms' parameter now a
	std::vector pointer.
	(find_oload_champ_namespace_loop): 'oload_syms' parameter now a
	std::vector pointer.  Adjust to new make_symbol_overload_list
	interface.
---
 gdb/cp-support.c | 142 ++++++++++++++++++++++++-------------------------------
 gdb/cp-support.h |  13 +++--
 gdb/valops.c     |  39 +++++++--------
 3 files changed, 87 insertions(+), 107 deletions(-)

diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 25c887035c..7079c31070 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -48,19 +48,19 @@ static unsigned int cp_find_first_component_aux (const char *name,
 
 static void demangled_name_complaint (const char *name);
 
-/* Functions/variables related to overload resolution.  */
-
-static int sym_return_val_size = -1;
-static int sym_return_val_index;
-static struct symbol **sym_return_val;
+/* Functions related to overload resolution.  */
 
 static void overload_list_add_symbol (struct symbol *sym,
-				      const char *oload_name);
+				      const char *oload_name,
+				      std::vector<symbol *> &overload_list);
 
-static void make_symbol_overload_list_using (const char *func_name,
-					     const char *the_namespace);
+static void add_symbol_overload_list_using
+  (const char *func_name, const char *the_namespace,
+   std::vector<symbol *> &overload_list);
 
-static void make_symbol_overload_list_qualified (const char *func_name);
+static void add_symbol_overload_list_qualified
+  (const char *func_name,
+   std::vector<symbol *> &overload_list);
 
 /* The list of "maint cplus" commands.  */
 
@@ -1137,30 +1137,28 @@ cp_entire_prefix_len (const char *name)
 /* Overload resolution functions.  */
 
 /* Test to see if SYM is a symbol that we haven't seen corresponding
-   to a function named OLOAD_NAME.  If so, add it to the current
-   completion list.  */
+   to a function named OLOAD_NAME.  If so, add it to
+   OVERLOAD_LIST.  */
 
 static void
 overload_list_add_symbol (struct symbol *sym,
-			  const char *oload_name)
+			  const char *oload_name,
+			  std::vector<symbol *> &overload_list)
 {
-  int newsize;
-  int i;
-  gdb::unique_xmalloc_ptr<char> sym_name;
-
   /* If there is no type information, we can't do anything, so
      skip.  */
   if (SYMBOL_TYPE (sym) == NULL)
     return;
 
   /* skip any symbols that we've already considered.  */
-  for (i = 0; i < sym_return_val_index; ++i)
+  for (symbol *listed_sym : overload_list)
     if (strcmp (SYMBOL_LINKAGE_NAME (sym),
-		SYMBOL_LINKAGE_NAME (sym_return_val[i])) == 0)
+		SYMBOL_LINKAGE_NAME (listed_sym)) == 0)
       return;
 
   /* Get the demangled name without parameters */
-  sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym));
+  gdb::unique_xmalloc_ptr<char> sym_name
+    = cp_remove_params (SYMBOL_NATURAL_NAME (sym));
   if (!sym_name)
     return;
 
@@ -1168,36 +1166,22 @@ overload_list_add_symbol (struct symbol *sym,
   if (strcmp (sym_name.get (), oload_name) != 0)
     return;
 
-  /* We have a match for an overload instance, so add SYM to the
-     current list of overload instances */
-  if (sym_return_val_index + 3 > sym_return_val_size)
-    {
-      newsize = (sym_return_val_size *= 2) * sizeof (struct symbol *);
-      sym_return_val = (struct symbol **)
-	xrealloc ((char *) sym_return_val, newsize);
-    }
-  sym_return_val[sym_return_val_index++] = sym;
-  sym_return_val[sym_return_val_index] = NULL;
+  overload_list.push_back (sym);
 }
 
 /* Return a null-terminated list of pointers to function symbols that
    are named FUNC_NAME and are visible within NAMESPACE.  */
 
-struct symbol **
+struct std::vector<symbol *>
 make_symbol_overload_list (const char *func_name,
 			   const char *the_namespace)
 {
-  struct cleanup *old_cleanups;
   const char *name;
+  std::vector<symbol *> overload_list;
 
-  sym_return_val_size = 100;
-  sym_return_val_index = 0;
-  sym_return_val = XNEWVEC (struct symbol *, sym_return_val_size + 1);
-  sym_return_val[0] = NULL;
-
-  old_cleanups = make_cleanup (xfree, sym_return_val);
+  overload_list.reserve (100);
 
-  make_symbol_overload_list_using (func_name, the_namespace);
+  add_symbol_overload_list_using (func_name, the_namespace, overload_list);
 
   if (the_namespace[0] == '\0')
     name = func_name;
@@ -1211,19 +1195,17 @@ make_symbol_overload_list (const char *func_name,
       name = concatenated_name;
     }
 
-  make_symbol_overload_list_qualified (name);
-
-  discard_cleanups (old_cleanups);
-
-  return sym_return_val;
+  add_symbol_overload_list_qualified (name, overload_list);
+  return overload_list;
 }
 
 /* Add all symbols with a name matching NAME in BLOCK to the overload
    list.  */
 
 static void
-make_symbol_overload_list_block (const char *name,
-                                 const struct block *block)
+add_symbol_overload_list_block (const char *name,
+				const struct block *block,
+				std::vector<symbol *> &overload_list)
 {
   struct block_iterator iter;
   struct symbol *sym;
@@ -1231,14 +1213,15 @@ make_symbol_overload_list_block (const char *name,
   lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
 
   ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
-    overload_list_add_symbol (sym, name);
+    overload_list_add_symbol (sym, name, overload_list);
 }
 
 /* Adds the function FUNC_NAME from NAMESPACE to the overload set.  */
 
 static void
-make_symbol_overload_list_namespace (const char *func_name,
-                                     const char *the_namespace)
+add_symbol_overload_list_namespace (const char *func_name,
+				    const char *the_namespace,
+				    std::vector<symbol *> &overload_list)
 {
   const char *name;
   const struct block *block = NULL;
@@ -1259,12 +1242,12 @@ make_symbol_overload_list_namespace (const char *func_name,
   /* Look in the static block.  */
   block = block_static_block (get_selected_block (0));
   if (block)
-    make_symbol_overload_list_block (name, block);
+    add_symbol_overload_list_block (name, block, overload_list);
 
   /* Look in the global block.  */
   block = block_global_block (block);
   if (block)
-    make_symbol_overload_list_block (name, block);
+    add_symbol_overload_list_block (name, block, overload_list);
 
 }
 
@@ -1272,8 +1255,9 @@ make_symbol_overload_list_namespace (const char *func_name,
    base types.  */
 
 static void
-make_symbol_overload_list_adl_namespace (struct type *type,
-                                         const char *func_name)
+add_symbol_overload_list_adl_namespace (struct type *type,
+					const char *func_name,
+					std::vector<symbol *> &overload_list)
 {
   char *the_namespace;
   const char *type_name;
@@ -1303,7 +1287,8 @@ make_symbol_overload_list_adl_namespace (struct type *type,
       strncpy (the_namespace, type_name, prefix_len);
       the_namespace[prefix_len] = '\0';
 
-      make_symbol_overload_list_namespace (func_name, the_namespace);
+      add_symbol_overload_list_namespace (func_name, the_namespace,
+					  overload_list);
     }
 
   /* Check public base type */
@@ -1311,28 +1296,23 @@ make_symbol_overload_list_adl_namespace (struct type *type,
     for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
       {
 	if (BASETYPE_VIA_PUBLIC (type, i))
-	  make_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type,
-								   i),
-						   func_name);
+	  add_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type, i),
+						  func_name,
+						  overload_list);
       }
 }
 
-/* Adds the overload list overload candidates for FUNC_NAME found
-   through argument dependent lookup.  */
+/* Adds to OVERLOAD_LIST the overload list overload candidates for
+   FUNC_NAME found through argument dependent lookup.  */
 
-struct symbol **
-make_symbol_overload_list_adl (struct type **arg_types, int nargs,
-                               const char *func_name)
+void
+add_symbol_overload_list_adl (gdb::array_view<type *> arg_types,
+			      const char *func_name,
+			      std::vector<symbol *> &overload_list)
 {
-  int i;
-
-  gdb_assert (sym_return_val_size != -1);
-
-  for (i = 1; i <= nargs; i++)
-    make_symbol_overload_list_adl_namespace (arg_types[i - 1],
-					     func_name);
-
-  return sym_return_val;
+  for (type *arg_type : arg_types)
+    add_symbol_overload_list_adl_namespace (arg_type, func_name,
+					    overload_list);
 }
 
 /* This applies the using directives to add namespaces to search in,
@@ -1341,8 +1321,9 @@ make_symbol_overload_list_adl (struct type **arg_types, int nargs,
    make_symbol_overload_list.  */
 
 static void
-make_symbol_overload_list_using (const char *func_name,
-				 const char *the_namespace)
+add_symbol_overload_list_using (const char *func_name,
+				const char *the_namespace,
+				std::vector<symbol *> &overload_list)
 {
   struct using_direct *current;
   const struct block *block;
@@ -1374,13 +1355,15 @@ make_symbol_overload_list_using (const char *func_name,
 	    scoped_restore reset_directive_searched
 	      = make_scoped_restore (&current->searched, 1);
 
-	    make_symbol_overload_list_using (func_name,
-					     current->import_src);
+	    add_symbol_overload_list_using (func_name,
+					    current->import_src,
+					    overload_list);
 	  }
       }
 
   /* Now, add names for this namespace.  */
-  make_symbol_overload_list_namespace (func_name, the_namespace);
+  add_symbol_overload_list_namespace (func_name, the_namespace,
+				      overload_list);
 }
 
 /* This does the bulk of the work of finding overloaded symbols.
@@ -1388,7 +1371,8 @@ make_symbol_overload_list_using (const char *func_name,
    (possibly including namespace info).  */
 
 static void
-make_symbol_overload_list_qualified (const char *func_name)
+add_symbol_overload_list_qualified (const char *func_name,
+				    std::vector<symbol *> &overload_list)
 {
   struct compunit_symtab *cust;
   struct objfile *objfile;
@@ -1407,7 +1391,7 @@ make_symbol_overload_list_qualified (const char *func_name)
      complete on local vars.  */
 
   for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
-    make_symbol_overload_list_block (func_name, b);
+    add_symbol_overload_list_block (func_name, b, overload_list);
 
   surrounding_static_block = block_static_block (get_selected_block (0));
 
@@ -1418,7 +1402,7 @@ make_symbol_overload_list_qualified (const char *func_name)
   {
     QUIT;
     b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
-    make_symbol_overload_list_block (func_name, b);
+    add_symbol_overload_list_block (func_name, b, overload_list);
   }
 
   ALL_COMPUNITS (objfile, cust)
@@ -1428,7 +1412,7 @@ make_symbol_overload_list_qualified (const char *func_name)
     /* Don't do this block twice.  */
     if (b == surrounding_static_block)
       continue;
-    make_symbol_overload_list_block (func_name, b);
+    add_symbol_overload_list_block (func_name, b, overload_list);
   }
 }
 
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 4e26921595..7278ba48ee 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -28,6 +28,8 @@
 #include "vec.h"
 #include "gdb_vecs.h"
 #include "gdb_obstack.h"
+#include "common/array-view.h"
+#include <vector>
 
 /* Opaque declarations.  */
 
@@ -107,12 +109,13 @@ extern gdb::unique_xmalloc_ptr<char> cp_remove_params
 extern gdb::unique_xmalloc_ptr<char> cp_remove_params_if_any
   (const char *demangled_name, bool completion_mode);
 
-extern struct symbol **make_symbol_overload_list (const char *,
-						  const char *);
+extern std::vector<symbol *> make_symbol_overload_list (const char *,
+							const char *);
 
-extern struct symbol **make_symbol_overload_list_adl (struct type **arg_types,
-                                                      int nargs,
-                                                      const char *func_name);
+extern void add_symbol_overload_list_adl
+  (gdb::array_view<type *> arg_types,
+   const char *func_name,
+   std::vector<symbol *> &overload_list);
 
 extern struct type *cp_lookup_rtti_type (const char *name,
 					 struct block *block);
diff --git a/gdb/valops.c b/gdb/valops.c
index f0e53a7ce9..d21980e726 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -56,13 +56,13 @@ static struct value *search_struct_method (const char *, struct value **,
 
 static int find_oload_champ_namespace (gdb::array_view<value *> args,
 				       const char *, const char *,
-				       struct symbol ***,
+				       std::vector<symbol *> *oload_syms,
 				       struct badness_vector **,
 				       const int no_adl);
 
 static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 					    const char *, const char *,
-					    int, struct symbol ***,
+					    int, std::vector<symbol *> *oload_syms,
 					    struct badness_vector **, int *,
 					    const int no_adl);
 
@@ -2517,8 +2517,8 @@ find_overload_match (gdb::array_view<value *> args,
   /* For methods, the list of overloaded methods.  */
   struct fn_field *fns_ptr = NULL;
   /* For non-methods, the list of overloaded function symbols.  */
-  struct symbol **oload_syms = NULL;
-  /* For xmethods, the vector of xmethod workers.  */
+  std::vector<symbol *> oload_syms;
+  /* For xmethods, the VEC of xmethod workers.  */
   std::vector<xmethod_worker_up> xm_worker_vec;
   /* Number of overloaded instances being considered.  */
   int num_fns = 0;
@@ -2717,7 +2717,6 @@ find_overload_match (gdb::array_view<value *> args,
 	func_match_quality = classify_oload_match (func_badness,
 						   args.size (), 0);
 
-      make_cleanup (xfree, oload_syms);
       make_cleanup (xfree, func_badness);
     }
 
@@ -2857,7 +2856,7 @@ static int
 find_oload_champ_namespace (gdb::array_view<value *> args,
 			    const char *func_name,
 			    const char *qualified_name,
-			    struct symbol ***oload_syms,
+			    std::vector<symbol *> *oload_syms,
 			    struct badness_vector **oload_champ_bv,
 			    const int no_adl)
 {
@@ -2887,17 +2886,15 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				 const char *func_name,
 				 const char *qualified_name,
 				 int namespace_len,
-				 struct symbol ***oload_syms,
+				 std::vector<symbol *> *oload_syms,
 				 struct badness_vector **oload_champ_bv,
 				 int *oload_champ,
 				 const int no_adl)
 {
   int next_namespace_len = namespace_len;
   int searched_deeper = 0;
-  int num_fns = 0;
   struct cleanup *old_cleanups;
   int new_oload_champ;
-  struct symbol **new_oload_syms;
   struct badness_vector *new_oload_champ_bv;
   char *new_namespace;
 
@@ -2910,7 +2907,6 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     cp_find_first_component (qualified_name + next_namespace_len);
 
   /* Initialize these to values that can safely be xfree'd.  */
-  *oload_syms = NULL;
   *oload_champ_bv = NULL;
 
   /* First, see if we have a deeper namespace we can search in.
@@ -2938,13 +2934,13 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
      because this overload mechanism only gets called if there's a
      function symbol to start off with.)  */
 
-  old_cleanups = make_cleanup (xfree, *oload_syms);
-  make_cleanup (xfree, *oload_champ_bv);
+  old_cleanups = make_cleanup (xfree, *oload_champ_bv);
   new_namespace = (char *) alloca (namespace_len + 1);
   strncpy (new_namespace, qualified_name, namespace_len);
   new_namespace[namespace_len] = '\0';
-  new_oload_syms = make_symbol_overload_list (func_name,
-					      new_namespace);
+
+  std::vector<symbol *> new_oload_syms
+    = make_symbol_overload_list (func_name, new_namespace);
 
   /* If we have reached the deepest level perform argument
      determined lookup.  */
@@ -2958,14 +2954,12 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 	alloca (args.size () * (sizeof (struct type *)));
       for (ix = 0; ix < args.size (); ix++)
 	arg_types[ix] = value_type (args[ix]);
-      make_symbol_overload_list_adl (arg_types, args.size (), func_name);
+      add_symbol_overload_list_adl ({arg_types, args.size ()}, func_name,
+				    new_oload_syms);
     }
 
-  while (new_oload_syms[num_fns])
-    ++num_fns;
-
-  new_oload_champ = find_oload_champ (args, num_fns,
-				      NULL, NULL, new_oload_syms,
+  new_oload_champ = find_oload_champ (args, new_oload_syms.size (),
+				      NULL, NULL, new_oload_syms.data (),
 				      &new_oload_champ_bv);
 
   /* Case 1: We found a good match.  Free earlier matches (if any),
@@ -2978,7 +2972,7 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
   if (new_oload_champ != -1
       && classify_oload_match (new_oload_champ_bv, args.size (), 0) == STANDARD)
     {
-      *oload_syms = new_oload_syms;
+      *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
       *oload_champ_bv = new_oload_champ_bv;
       do_cleanups (old_cleanups);
@@ -2986,14 +2980,13 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     }
   else if (searched_deeper)
     {
-      xfree (new_oload_syms);
       xfree (new_oload_champ_bv);
       discard_cleanups (old_cleanups);
       return 0;
     }
   else
     {
-      *oload_syms = new_oload_syms;
+      *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
       *oload_champ_bv = new_oload_champ_bv;
       do_cleanups (old_cleanups);
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends
  2018-10-15 15:11 [PATCH 0/6] Use gdb::array_view some more, plug leaks Pedro Alves
  2018-10-15 15:11 ` [PATCH 5/6] valops.c: Some more gdb::array_view Pedro Alves
  2018-10-15 15:11 ` [PATCH 3/6] Eliminate make_symbol_overload_list-related globals & cleanup Pedro Alves
@ 2018-10-15 15:11 ` Pedro Alves
  2018-10-17  1:45   ` Simon Marchi
  2018-10-15 15:11 ` [PATCH 2/6] invoke_xmethod & array_view Pedro Alves
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2018-10-15 15:11 UTC (permalink / raw)
  To: gdb-patches

This replaces a few uses of pointer+length with gdb::array_view, in
call_function_by_hand and related code.

Unfortunately, due to -Wnarrowing, there are places where we can't
brace-initialize an gdb::array_view without an ugly-ish cast.  To
avoid the cast, this patch introduces a gdb::make_array_view function.
Unit tests included.

This patch in isolation may not look so interesting, due to
gdb::make_array_view uses, but I think it's still worth it.  Some of
the gdb::make_array_view calls disappear down the series, and others
could be eliminated with more (non-trivial) gdb::array_view
detangling/conversion (e.g. code around eval_call).  See this as a "we
have to start somewhere" patch.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* ada-lang.c (ada_evaluate_subexp): Adjust to pass an array_view.
	* common/array-view.h (make_array_view): New.
	* compile/compile-object-run.c (compile_object_run): Adjust to
	pass an array_view.
	* elfread.c (elf_gnu_ifunc_resolve_addr): Adjust.
	* eval.c (eval_call): Adjust to pass an array_view.
	(evaluate_subexp_standard): Adjust to pass an array_view.
	* gcore.c (call_target_sbrk): Adjust to pass an array_view.
	* guile/scm-value.c (gdbscm_value_call): Likewise.
	* infcall.c (push_dummy_code): Replace pointer + size parameters
	with an array_view parameter.
	(call_function_by_hand, call_function_by_hand_dummy): Likewise and
	adjust.
	* infcall.h: Include "common/array-view.h".
	(call_function_by_hand, call_function_by_hand_dummy): Replace
	pointer + size parameters with an array_view parameter.
	* linux-fork.c (inferior_call_waitpid): Adjust to use array_view.
	* linux-tdep.c (linux_infcall_mmap): Likewise.
	* objc-lang.c (lookup_objc_class, lookup_child_selector)
	(value_nsstring, print_object_command): Likewise.
	* python/py-value.c (valpy_call): Likewise.
	* rust-lang.c (rust_evaluate_funcall): Likewise.
	* valarith.c (value_x_binop, value_x_unop): Likewise.
	* valops.c (value_allocate_space_in_inferior): Likewise.
	* unittests/array-view-selftests.c (run_tests): Add
	gdb::make_array_view test.
---
 gdb/ada-lang.c                       |  4 +++-
 gdb/common/array-view.h              | 41 ++++++++++++++++++++++++++++++++++++
 gdb/compile/compile-object-run.c     |  4 ++--
 gdb/elfread.c                        |  2 +-
 gdb/eval.c                           | 18 ++++++++--------
 gdb/gcore.c                          |  2 +-
 gdb/guile/scm-value.c                |  4 ++--
 gdb/infcall.c                        | 29 +++++++++++++------------
 gdb/infcall.h                        |  7 +++---
 gdb/linux-fork.c                     |  7 +++---
 gdb/linux-tdep.c                     |  4 ++--
 gdb/objc-lang.c                      | 13 ++++++------
 gdb/python/py-value.c                |  6 +++---
 gdb/rust-lang.c                      |  2 +-
 gdb/unittests/array-view-selftests.c | 13 ++++++++++++
 gdb/valarith.c                       |  7 +++---
 gdb/valops.c                         |  2 +-
 17 files changed, 110 insertions(+), 55 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 1462271a71..de9f201cf3 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10985,7 +10985,9 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 		error_call_unknown_return_type (NULL);
 	      return allocate_value (TYPE_TARGET_TYPE (type));
 	    }
-	  return call_function_by_hand (argvec[0], NULL, nargs, argvec + 1);
+	  return call_function_by_hand (argvec[0], NULL,
+					gdb::make_array_view (argvec + 1,
+							      nargs));
 	case TYPE_CODE_INTERNAL_FUNCTION:
 	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	    /* We don't know anything about what the internal
diff --git a/gdb/common/array-view.h b/gdb/common/array-view.h
index 319ea99468..45d1a4720e 100644
--- a/gdb/common/array-view.h
+++ b/gdb/common/array-view.h
@@ -201,6 +201,47 @@ operator!= (const gdb::array_view<T> &lhs, const gdb::array_view<T> &rhs)
   return !(lhs == rhs);
 }
 
+/* Create an array view from a pointer to an array and an element
+   count.
+
+   This is useful as alternative to constructing an array_view using
+   brace initialization when the size variable you have handy is of
+   signed type, since otherwise without an explicit cast the code
+   would be ill-formed.
+
+   For example, with:
+
+     extern void foo (int, int, gdb::array_view<value *>);
+
+     value *args[2];
+     int nargs;
+     foo (1, 2, {values, nargs});
+
+   You'd get:
+
+     source.c:10: error: narrowing conversion of ‘nargs’ from ‘int’ to ‘size_t {aka long unsigned int}’ inside { } [-Werror=narrowing]
+
+   You could fix it by writing the somewhat distracting explicit cast:
+
+     foo (1, 2, {values, (size_t) nargs});
+
+   Or by instantiating an array_view explicitly:
+
+     foo (1, 2, gdb::array_view<value *>(values, nargs));
+
+   Or, better, using make_array_view, which has the advantage of
+   inferring the arrav_view element's type:
+
+     foo (1, 2, gdb::make_array_view (values, nargs));
+*/
+
+template<typename U>
+constexpr inline array_view<U>
+make_array_view (U *array, size_t size) noexcept
+{
+  return {array, size};
+}
+
 } /* namespace gdb */
 
 #endif
diff --git a/gdb/compile/compile-object-run.c b/gdb/compile/compile-object-run.c
index f3ec932365..e891e77fba 100644
--- a/gdb/compile/compile-object-run.c
+++ b/gdb/compile/compile-object-run.c
@@ -170,8 +170,8 @@ compile_object_run (struct compile_module *module)
 	  ++current_arg;
 	}
       gdb_assert (current_arg == TYPE_NFIELDS (func_type));
-      call_function_by_hand_dummy (func_val,
-				   NULL, TYPE_NFIELDS (func_type), vargs,
+      auto args = gdb::make_array_view (vargs, TYPE_NFIELDS (func_type));
+      call_function_by_hand_dummy (func_val, NULL, args,
 				   do_module_cleanup, data);
     }
   CATCH (ex, RETURN_MASK_ERROR)
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 9f1fa2bec4..71e6fcca6e 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -904,7 +904,7 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   target_auxv_search (current_top_target (), AT_HWCAP, &hwcap);
   hwcap_val = value_from_longest (builtin_type (gdbarch)
 				  ->builtin_unsigned_long, hwcap);
-  address_val = call_function_by_hand (function, NULL, 1, &hwcap_val);
+  address_val = call_function_by_hand (function, NULL, hwcap_val);
   address = value_as_address (address_val);
   address = gdbarch_convert_from_func_ptr_addr (gdbarch, address, current_top_target ());
   address = gdbarch_addr_bits_remove (gdbarch, address);
diff --git a/gdb/eval.c b/gdb/eval.c
index 5ee59908ba..255d51b0a2 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -830,7 +830,7 @@ eval_call (expression *exp, enum noside noside,
       return call_xmethod (argvec[0], nargs, argvec + 1);
     default:
       return call_function_by_hand (argvec[0], default_return_type,
-				    nargs, argvec + 1);
+				    gdb::make_array_view (argvec + 1, nargs));
     }
 }
 
@@ -1729,12 +1729,12 @@ evaluate_subexp_standard (struct type *expect_type,
 	argvec[3] = value_from_longest (long_type, selector);
 	argvec[4] = 0;
 
-	ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	if (gnu_runtime)
 	  {
 	    /* Function objc_msg_lookup returns a pointer.  */
 	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	    ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	  }
 	if (value_as_long (ret) == 0)
 	  error (_("Target does not respond to this message selector."));
@@ -1751,11 +1751,11 @@ evaluate_subexp_standard (struct type *expect_type,
 	argvec[3] = value_from_longest (long_type, selector);
 	argvec[4] = 0;
 
-	ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	if (gnu_runtime)
 	  {
 	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	    ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	  }
 
 	/* ret should now be the selector.  */
@@ -1891,17 +1891,17 @@ evaluate_subexp_standard (struct type *expect_type,
 	  argvec[tem + 3] = evaluate_subexp_with_coercion (exp, pos, noside);
 	argvec[tem + 3] = 0;
 
+	auto call_args = gdb::make_array_view (argvec + 1, nargs + 2);
+
 	if (gnu_runtime && (method != NULL))
 	  {
 	    /* Function objc_msg_lookup returns a pointer.  */
 	    deprecated_set_value_type (argvec[0],
 				       lookup_pointer_type (lookup_function_type (value_type (argvec[0]))));
-	    argvec[0]
-	      = call_function_by_hand (argvec[0], NULL, nargs + 2, argvec + 1);
+	    argvec[0] = call_function_by_hand (argvec[0], NULL, call_args);
 	  }
 
-	ret = call_function_by_hand (argvec[0], NULL, nargs + 2, argvec + 1);
-	return ret;
+	return call_function_by_hand (argvec[0], NULL, call_args);
       }
       break;
 
diff --git a/gdb/gcore.c b/gdb/gcore.c
index fbebb6af18..24810a7dee 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -300,7 +300,7 @@ call_target_sbrk (int sbrk_arg)
   target_sbrk_arg = value_from_longest (builtin_type (gdbarch)->builtin_int, 
 					sbrk_arg);
   gdb_assert (target_sbrk_arg);
-  ret = call_function_by_hand (sbrk_fn, NULL, 1, &target_sbrk_arg);
+  ret = call_function_by_hand (sbrk_fn, NULL, target_sbrk_arg);
   if (ret == NULL)
     return (bfd_vma) 0;
 
diff --git a/gdb/guile/scm-value.c b/gdb/guile/scm-value.c
index ca0c075f5c..42afd609f6 100644
--- a/gdb/guile/scm-value.c
+++ b/gdb/guile/scm-value.c
@@ -730,8 +730,8 @@ gdbscm_value_call (SCM self, SCM args)
     {
       scoped_value_mark free_values;
 
-      value *return_value = call_function_by_hand (function, NULL,
-						   args_count, vargs);
+      auto av = gdb::make_array_view (vargs, args_count);
+      value *return_value = call_function_by_hand (function, NULL, av);
       return vlscm_scm_from_value (return_value);
     });
 }
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 96d43704fa..4a8a5ee9ed 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -334,7 +334,7 @@ find_function_addr (struct value *function,
 static CORE_ADDR
 push_dummy_code (struct gdbarch *gdbarch,
 		 CORE_ADDR sp, CORE_ADDR funaddr,
-		 struct value **args, int nargs,
+		 gdb::array_view<value *> args,
 		 struct type *value_type,
 		 CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
 		 struct regcache *regcache)
@@ -342,7 +342,8 @@ push_dummy_code (struct gdbarch *gdbarch,
   gdb_assert (gdbarch_push_dummy_code_p (gdbarch));
 
   return gdbarch_push_dummy_code (gdbarch, sp, funaddr,
-				  args, nargs, value_type, real_pc, bp_addr,
+				  args.data (), args.size (),
+				  value_type, real_pc, bp_addr,
 				  regcache);
 }
 
@@ -686,10 +687,10 @@ cleanup_delete_std_terminate_breakpoint (void *ignore)
 struct value *
 call_function_by_hand (struct value *function,
 		       type *default_return_type,
-		       int nargs, struct value **args)
+		       gdb::array_view<value *> args)
 {
   return call_function_by_hand_dummy (function, default_return_type,
-				      nargs, args, NULL, NULL);
+				      args, NULL, NULL);
 }
 
 /* All this stuff with a dummy frame may seem unnecessarily complicated
@@ -713,7 +714,7 @@ call_function_by_hand (struct value *function,
 struct value *
 call_function_by_hand_dummy (struct value *function,
 			     type *default_return_type,
-			     int nargs, struct value **args,
+			     gdb::array_view<value *> args,
 			     dummy_frame_dtor_ftype *dummy_dtor,
 			     void *dummy_dtor_data)
 {
@@ -920,7 +921,7 @@ call_function_by_hand_dummy (struct value *function,
 	/* Be careful BP_ADDR is in inferior PC encoding while
 	   BP_ADDR_AS_ADDRESS is a plain memory address.  */
 
-	sp = push_dummy_code (gdbarch, sp, funaddr, args, nargs,
+	sp = push_dummy_code (gdbarch, sp, funaddr, args,
 			      target_values_type, &real_pc, &bp_addr,
 			      get_current_regcache ());
 
@@ -961,14 +962,14 @@ call_function_by_hand_dummy (struct value *function,
       internal_error (__FILE__, __LINE__, _("bad switch"));
     }
 
-  if (nargs < TYPE_NFIELDS (ftype))
+  if (args.size () < TYPE_NFIELDS (ftype))
     error (_("Too few arguments in function call."));
 
-  for (int i = nargs - 1; i >= 0; i--)
+  for (int i = args.size () - 1; i >= 0; i--)
     {
       int prototyped;
       struct type *param_type;
-	
+
       /* FIXME drow/2002-05-31: Should just always mark methods as
 	 prototyped.  Can we respect TYPE_VARARGS?  Probably not.  */
       if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
@@ -1045,22 +1046,22 @@ call_function_by_hand_dummy (struct value *function,
 	}
     }
 
-  std::vector<struct value *> new_args;
+  std::vector<value *> new_args;
   if (hidden_first_param_p)
     {
       /* Add the new argument to the front of the argument list.  */
+      new_args.reserve (args.size ());
       new_args.push_back
 	(value_from_pointer (lookup_pointer_type (values_type), struct_addr));
-      std::copy (&args[0], &args[nargs], std::back_inserter (new_args));
-      args = new_args.data ();
-      nargs++;
+      new_args.insert (new_args.end (), args.begin (), args.end ());
+      args = new_args;
     }
 
   /* Create the dummy stack frame.  Pass in the call dummy address as,
      presumably, the ABI code knows where, in the call dummy, the
      return address should be pointed.  */
   sp = gdbarch_push_dummy_call (gdbarch, function, get_current_regcache (),
-				bp_addr, nargs, args,
+				bp_addr, args.size (), args.data (),
 				sp, struct_return, struct_addr);
 
   /* Set up a frame ID for the dummy frame so we can pass it to
diff --git a/gdb/infcall.h b/gdb/infcall.h
index 8b2195019c..878fb0dba5 100644
--- a/gdb/infcall.h
+++ b/gdb/infcall.h
@@ -21,6 +21,7 @@
 #define INFCALL_H
 
 #include "dummy-frame.h"
+#include "common/array-view.h"
 
 struct value;
 struct type;
@@ -50,8 +51,7 @@ extern CORE_ADDR find_function_addr (struct value *function,
 
 extern struct value *call_function_by_hand (struct value *function,
 					    type *default_return_type,
-					    int nargs,
-					    struct value **args);
+					    gdb::array_view<value *> args);
 
 /* Similar to call_function_by_hand and additional call
    register_dummy_frame_dtor with DUMMY_DTOR and DUMMY_DTOR_DATA for the
@@ -60,8 +60,7 @@ extern struct value *call_function_by_hand (struct value *function,
 extern struct value *
   call_function_by_hand_dummy (struct value *function,
 			       type *default_return_type,
-			       int nargs,
-			       struct value **args,
+			       gdb::array_view<value *> args,
 			       dummy_frame_dtor_ftype *dummy_dtor,
 			       void *dummy_dtor_data);
 
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 74d5c195d2..0f87d97c6e 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -456,7 +456,7 @@ inferior_call_waitpid (ptid_t pptid, int pid)
 {
   struct objfile *waitpid_objf;
   struct value *waitpid_fn = NULL;
-  struct value *argv[4], *retv;
+  struct value *argv[3], *retv;
   struct gdbarch *gdbarch = get_current_arch ();
   struct fork_info *oldfp = NULL, *newfp = NULL;
   struct cleanup *old_cleanup;
@@ -490,9 +490,8 @@ inferior_call_waitpid (ptid_t pptid, int pid)
   argv[0] = value_from_longest (builtin_type (gdbarch)->builtin_int, pid);
   argv[1] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr, 0);
   argv[2] = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
-  argv[3] = 0;
 
-  retv = call_function_by_hand (waitpid_fn, NULL, 3, argv);
+  retv = call_function_by_hand (waitpid_fn, NULL, argv);
   if (value_as_long (retv) < 0)
     goto out;
 
@@ -704,7 +703,7 @@ checkpoint_command (const char *args, int from_tty)
     scoped_restore save_pid
       = make_scoped_restore (&checkpointing_pid, inferior_ptid.pid ());
 
-    ret = call_function_by_hand (fork_fn, NULL, 0, &ret);
+    ret = call_function_by_hand (fork_fn, NULL, {});
   }
 
   if (!ret)	/* Probably can't happen.  */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 352114943f..3b76f7e550 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -2398,7 +2398,7 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
   arg[ARG_FD] = value_from_longest (builtin_type (gdbarch)->builtin_int, -1);
   arg[ARG_OFFSET] = value_from_longest (builtin_type (gdbarch)->builtin_int64,
 					0);
-  addr_val = call_function_by_hand (mmap_val, NULL, ARG_LAST, arg);
+  addr_val = call_function_by_hand (mmap_val, NULL, arg);
   retval = value_as_address (addr_val);
   if (retval == (CORE_ADDR) -1)
     error (_("Failed inferior mmap call for %s bytes, errno is changed."),
@@ -2427,7 +2427,7 @@ linux_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
   /* Assuming sizeof (unsigned long) == sizeof (size_t).  */
   arg[ARG_LENGTH] = value_from_ulongest
 		    (builtin_type (gdbarch)->builtin_unsigned_long, size);
-  retval_val = call_function_by_hand (munmap_val, NULL, ARG_LAST, arg);
+  retval_val = call_function_by_hand (munmap_val, NULL, arg);
   retval = value_as_long (retval_val);
   if (retval != 0)
     warning (_("Failed inferior munmap call at %s for %s bytes, "
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 6da8af1a46..d51362a4d3 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -132,7 +132,7 @@ lookup_objc_class (struct gdbarch *gdbarch, const char *classname)
   classval = value_coerce_array (classval);
   return (CORE_ADDR) value_as_long (call_function_by_hand (function,
 							   NULL,
-							   1, &classval));
+							   classval));
 }
 
 CORE_ADDR
@@ -160,7 +160,7 @@ lookup_child_selector (struct gdbarch *gdbarch, const char *selname)
   selstring = value_coerce_array (value_string (selname, 
 						strlen (selname) + 1,
 						char_type));
-  return value_as_long (call_function_by_hand (function, NULL, 1, &selstring));
+  return value_as_long (call_function_by_hand (function, NULL, selstring));
 }
 
 struct value * 
@@ -181,13 +181,12 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
   if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0).minsym)
     {
       function = find_function_in_inferior("_NSNewStringFromCString", NULL);
-      nsstringValue = call_function_by_hand(function,
-					    NULL, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function, NULL, stringValue[2]);
     }
   else if (lookup_minimal_symbol("istr", 0, 0).minsym)
     {
       function = find_function_in_inferior("istr", NULL);
-      nsstringValue = call_function_by_hand(function, NULL, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function, NULL, stringValue[2]);
     }
   else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0).minsym)
     {
@@ -199,7 +198,7 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
 	(type, lookup_objc_class (gdbarch, "NSString"));
       stringValue[1] = value_from_longest 
 	(type, lookup_child_selector (gdbarch, "stringWithCString:"));
-      nsstringValue = call_function_by_hand(function, NULL, 3, &stringValue[0]);
+      nsstringValue = call_function_by_hand(function, NULL, stringValue);
     }
   else
     error (_("NSString: internal error -- no way to create new NSString"));
@@ -1189,7 +1188,7 @@ print_object_command (const char *args, int from_tty)
   if (function == NULL)
     error (_("Unable to locate _NSPrintForDebugger in child process"));
 
-  description = call_function_by_hand (function, NULL, 1, &object);
+  description = call_function_by_hand (function, NULL, object);
 
   string_addr = value_as_long (description);
   if (string_addr == 0)
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 26e91ff2b2..b23bdbb02e 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -917,10 +917,10 @@ valpy_call (PyObject *self, PyObject *args, PyObject *keywords)
   TRY
     {
       scoped_value_mark free_values;
-      struct value *return_value;
 
-      return_value = call_function_by_hand (function, NULL,
-					    args_count, vargs);
+      value *return_value
+	= call_function_by_hand (function, NULL,
+				 gdb::make_array_view (vargs, args_count));
       result = value_to_value_object (return_value);
     }
   CATCH (except, RETURN_MASK_ALL)
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 152413a612..abd3076f87 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1158,7 +1158,7 @@ rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     result = value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
   else
-    result = call_function_by_hand (function, NULL, num_args + 1, args.data ());
+    result = call_function_by_hand (function, NULL, args);
   return result;
 }
 
diff --git a/gdb/unittests/array-view-selftests.c b/gdb/unittests/array-view-selftests.c
index 3116ab2721..74defa1b40 100644
--- a/gdb/unittests/array-view-selftests.c
+++ b/gdb/unittests/array-view-selftests.c
@@ -483,6 +483,19 @@ run_tests ()
     gdb::array_view<Vec> view_elem = elem;
     SELF_CHECK (view_elem.size () == 1);
   }
+
+  /* gdb::make_array_view, int length.  */
+  {
+    gdb_byte data[] = {0x55, 0x66, 0x77, 0x88};
+    int len = sizeof (data) / sizeof (data[0]);
+    auto view = gdb::make_array_view (data, len);
+
+    SELF_CHECK (view.data () == data);
+    SELF_CHECK (view.size () == len);
+
+    for (size_t i = 0; i < len; i++)
+      SELF_CHECK (view[i] == data[i]);
+  }
 }
 
 } /* namespace array_view_tests */
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 807cdd5dbd..875f5477c2 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -502,8 +502,8 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	    = TYPE_TARGET_TYPE (check_typedef (value_type (argvec[0])));
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
-      return call_function_by_hand (argvec[0], NULL, 2 - static_memfuncp,
-				    argvec + 1);
+      return call_function_by_hand (argvec[0], NULL,
+				    {argvec + 1, 2u - static_memfuncp});
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
@@ -618,7 +618,8 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	    = TYPE_TARGET_TYPE (check_typedef (value_type (argvec[0])));
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
-      return call_function_by_hand (argvec[0], NULL, nargs, argvec + 1);
+      return call_function_by_hand (argvec[0], NULL,
+				    gdb::make_array_view (argvec + 1, nargs));
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
diff --git a/gdb/valops.c b/gdb/valops.c
index c45caefbf1..4758b5cdfc 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -184,7 +184,7 @@ value_allocate_space_in_inferior (int len)
   struct value *blocklen;
 
   blocklen = value_from_longest (builtin_type (gdbarch)->builtin_int, len);
-  val = call_function_by_hand (val, NULL, 1, &blocklen);
+  val = call_function_by_hand (val, NULL, blocklen);
   if (value_logical_not (val))
     {
       if (!target_has_execution)
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 4/6] C++ify badness_vector, fix leaks
  2018-10-15 15:11 [PATCH 0/6] Use gdb::array_view some more, plug leaks Pedro Alves
                   ` (3 preceding siblings ...)
  2018-10-15 15:11 ` [PATCH 2/6] invoke_xmethod & array_view Pedro Alves
@ 2018-10-15 15:16 ` Pedro Alves
  2018-10-17 17:44   ` Simon Marchi
  2018-10-15 15:18 ` [PATCH 6/6] valops.c: Overload resolution code: Rename parameters/locals Pedro Alves
  5 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2018-10-15 15:16 UTC (permalink / raw)
  To: gdb-patches

badness_vector is currenlty an open coded vector.  This reimplements
it as a std::vector.

This fixes a few leaks as well:

 - find_oload_champ is leaking every badness vector calculated bar the
   one returned.

 - bv->rank is always leaked, since callers of rank_function only
   xfree the badness_vector pointer, not bv->rank.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdbtypes.c (compare_badness): Change type of parameters to const
	reference.  Adjust to badness_vector being a std::vector now.
	(rank_function): Adjust to badness_vector being a std::vector now.
	* gdbtypes.h (badness_vector): Now a typedef to std::vector.
	(LENGTH_MATCH): Delete.
	(compare_badness): Change type of parameters to const reference.
	(rank_function): Return a badness_vector by value now.
	(find_overload_match): Adjust to badness_vector being a
	std::vector now.  Remove cleanups.
	(find_oload_champ_namespace): 'oload_champ_bv' parameter now a
	badness_vector pointer.
	(find_oload_champ_namespace_loop): 'oload_champ_bv' parameter now
	a badness_vector pointer.  Adjust to badness_vector being a
	std::vector now.  Remove cleanups.
	(find_oload_champ): 'oload_champ_bv' parameter now
	a badness_vector pointer.  Adjust to badness_vector being a
	std::vector now.  Remove cleanups.
---
 gdb/gdbtypes.c | 43 +++++++++++++++++------------------
 gdb/gdbtypes.h | 17 +++++---------
 gdb/valops.c   | 71 +++++++++++++++++++++-------------------------------------
 3 files changed, 53 insertions(+), 78 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 4160d996de..39b7a99017 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3426,21 +3426,21 @@ compare_ranks (struct rank a, struct rank b)
    3 => A is worse than B  */
 
 int
-compare_badness (struct badness_vector *a, struct badness_vector *b)
+compare_badness (const badness_vector &a, const badness_vector &b)
 {
   int i;
   int tmp;
   short found_pos = 0;		/* any positives in c? */
   short found_neg = 0;		/* any negatives in c? */
 
-  /* differing lengths => incomparable */
-  if (a->length != b->length)
+  /* differing sizes => incomparable */
+  if (a.size () != b.size ())
     return 1;
 
   /* Subtract b from a */
-  for (i = 0; i < a->length; i++)
+  for (i = 0; i < a.size (); i++)
     {
-      tmp = compare_ranks (b->rank[i], a->rank[i]);
+      tmp = compare_ranks (b[i], a[i]);
       if (tmp > 0)
 	found_pos = 1;
       else if (tmp < 0)
@@ -3465,19 +3465,16 @@ compare_badness (struct badness_vector *a, struct badness_vector *b)
 }
 
 /* Rank a function by comparing its parameter types (PARMS), to the
-   types of an argument list (ARGS).  Return a pointer to a badness
-   vector.  This has ARGS.size() + 1 entries.  */
+   types of an argument list (ARGS).  Return the badness vector.  This
+   has ARGS.size() + 1 entries.  */
 
-struct badness_vector *
+badness_vector
 rank_function (gdb::array_view<type *> parms,
 	       gdb::array_view<value *> args)
 {
-  int i;
-  struct badness_vector *bv = XNEW (struct badness_vector);
-  size_t min_len = std::min (parms.size (), args.size ());
-
-  bv->length = args.size () + 1;	/* add 1 for the length-match rank.  */
-  bv->rank = XNEWVEC (struct rank, args.size () + 1);
+  /* add 1 for the length-match rank.  */
+  badness_vector bv;
+  bv.reserve (1 + args.size ());
 
   /* First compare the lengths of the supplied lists.
      If there is a mismatch, set it to a high value.  */
@@ -3486,18 +3483,20 @@ rank_function (gdb::array_view<type *> parms,
      arguments and ellipsis parameter lists, we should consider those
      and rank the length-match more finely.  */
 
-  LENGTH_MATCH (bv) = (args.size () != parms.size ())
-		      ? LENGTH_MISMATCH_BADNESS
-		      : EXACT_MATCH_BADNESS;
+  bv.push_back ((args.size () != parms.size ())
+		? LENGTH_MISMATCH_BADNESS
+		: EXACT_MATCH_BADNESS);
 
   /* Now rank all the parameters of the candidate function.  */
-  for (i = 1; i <= min_len; i++)
-    bv->rank[i] = rank_one_type (parms[i - 1], value_type (args[i - 1]),
-				 args[i - 1]);
+  size_t min_len = std::min (parms.size (), args.size ());
+
+  for (size_t i = 0; i < min_len; i++)
+    bv.push_back (rank_one_type (parms[i], value_type (args[i]),
+				 args[i]));
 
   /* If more arguments than parameters, add dummy entries.  */
-  for (i = min_len + 1; i <= args.size (); i++)
-    bv->rank[i] = TOO_FEW_PARAMS_BADNESS;
+  for (size_t i = min_len; i < args.size (); i++)
+    bv.push_back (TOO_FEW_PARAMS_BADNESS);
 
   return bv;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 731b18d082..f0adec7a20 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1095,13 +1095,9 @@ struct rank
     short subrank;
   };
 
-/* * Struct used for ranking a function for overload resolution.  */
+/* * Used for ranking a function for overload resolution.  */
 
-struct badness_vector
-  {
-    int length;
-    struct rank *rank;
-  };
+typedef std::vector<rank> badness_vector;
 
 /* * GNAT Ada-specific information for various Ada types.  */
 
@@ -1983,8 +1979,6 @@ extern int is_unique_ancestor (struct type *, struct value *);
 
 /* Overload resolution */
 
-#define LENGTH_MATCH(bv) ((bv)->rank[0])
-
 /* * Badness if parameter list length doesn't match arg list length.  */
 extern const struct rank LENGTH_MISMATCH_BADNESS;
 
@@ -2043,10 +2037,11 @@ extern const struct rank NS_INTEGER_POINTER_CONVERSION_BADNESS;
 extern struct rank sum_ranks (struct rank a, struct rank b);
 extern int compare_ranks (struct rank a, struct rank b);
 
-extern int compare_badness (struct badness_vector *, struct badness_vector *);
+extern int compare_badness (const badness_vector &,
+			    const badness_vector &);
 
-extern struct badness_vector *rank_function (gdb::array_view<type *> parms,
-					     gdb::array_view<value *> args);
+extern badness_vector rank_function (gdb::array_view<type *> parms,
+				     gdb::array_view<value *> args);
 
 extern struct rank rank_one_type (struct type *, struct type *,
 				  struct value *);
diff --git a/gdb/valops.c b/gdb/valops.c
index d21980e726..1cf3fd8fd5 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -57,27 +57,26 @@ static struct value *search_struct_method (const char *, struct value **,
 static int find_oload_champ_namespace (gdb::array_view<value *> args,
 				       const char *, const char *,
 				       std::vector<symbol *> *oload_syms,
-				       struct badness_vector **,
+				       badness_vector *,
 				       const int no_adl);
 
 static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 					    const char *, const char *,
 					    int, std::vector<symbol *> *oload_syms,
-					    struct badness_vector **, int *,
+					    badness_vector *, int *,
 					    const int no_adl);
 
 static int find_oload_champ (gdb::array_view<value *> args, int,
 			     struct fn_field *,
 			     const std::vector<xmethod_worker_up> *,
-			     struct symbol **, struct badness_vector **);
+			     struct symbol **, badness_vector *);
 
 static int oload_method_static_p (struct fn_field *, int);
 
 enum oload_classification { STANDARD, NON_STANDARD, INCOMPATIBLE };
 
-static enum
-oload_classification classify_oload_match (struct badness_vector *,
-					   int, int);
+static enum oload_classification classify_oload_match
+  (const badness_vector &, int, int);
 
 static struct value *value_struct_elt_for_reference (struct type *,
 						     int, struct type *,
@@ -2508,10 +2507,10 @@ find_overload_match (gdb::array_view<value *> args,
   int ext_method_oload_champ = -1;
 
   /* The measure for the current best match.  */
-  struct badness_vector *method_badness = NULL;
-  struct badness_vector *func_badness = NULL;
-  struct badness_vector *ext_method_badness = NULL;
-  struct badness_vector *src_method_badness = NULL;
+  badness_vector method_badness;
+  badness_vector func_badness;
+  badness_vector ext_method_badness;
+  badness_vector src_method_badness;
 
   struct value *temp = obj;
   /* For methods, the list of overloaded methods.  */
@@ -2584,8 +2583,6 @@ find_overload_match (gdb::array_view<value *> args,
 	  src_method_match_quality = classify_oload_match
 	    (src_method_badness, args.size (),
 	     oload_method_static_p (fns_ptr, src_method_oload_champ));
-
-	  make_cleanup (xfree, src_method_badness);
 	}
 
       if (!xm_worker_vec.empty ())
@@ -2594,7 +2591,6 @@ find_overload_match (gdb::array_view<value *> args,
 						     NULL, &ext_method_badness);
 	  ext_method_match_quality = classify_oload_match (ext_method_badness,
 							   args.size (), 0);
-	  make_cleanup (xfree, ext_method_badness);
 	}
 
       if (src_method_oload_champ >= 0 && ext_method_oload_champ >= 0)
@@ -2716,8 +2712,6 @@ find_overload_match (gdb::array_view<value *> args,
       if (func_oload_champ >= 0)
 	func_match_quality = classify_oload_match (func_badness,
 						   args.size (), 0);
-
-      make_cleanup (xfree, func_badness);
     }
 
   /* Did we find a match ?  */
@@ -2848,7 +2842,7 @@ find_overload_match (gdb::array_view<value *> args,
    contained in QUALIFIED_NAME until it either finds a good match or
    runs out of namespaces.  It stores the overloaded functions in
    *OLOAD_SYMS, and the badness vector in *OLOAD_CHAMP_BV.  The
-   calling function is responsible for freeing *OLOAD_SYMS and
+   calling function is responsible for clearing *OLOAD_SYMS and
    *OLOAD_CHAMP_BV.  If NO_ADL, argument dependent lookup is not 
    performned.  */
 
@@ -2857,7 +2851,7 @@ find_oload_champ_namespace (gdb::array_view<value *> args,
 			    const char *func_name,
 			    const char *qualified_name,
 			    std::vector<symbol *> *oload_syms,
-			    struct badness_vector **oload_champ_bv,
+			    badness_vector *oload_champ_bv,
 			    const int no_adl)
 {
   int oload_champ;
@@ -2878,7 +2872,7 @@ find_oload_champ_namespace (gdb::array_view<value *> args,
    if it isn't.  Other arguments are the same as in
    find_oload_champ_namespace
 
-   It is the caller's responsibility to free *OLOAD_SYMS and
+   It is the caller's responsibility to clear *OLOAD_SYMS and
    *OLOAD_CHAMP_BV.  */
 
 static int
@@ -2887,15 +2881,13 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				 const char *qualified_name,
 				 int namespace_len,
 				 std::vector<symbol *> *oload_syms,
-				 struct badness_vector **oload_champ_bv,
+				 badness_vector *oload_champ_bv,
 				 int *oload_champ,
 				 const int no_adl)
 {
   int next_namespace_len = namespace_len;
   int searched_deeper = 0;
-  struct cleanup *old_cleanups;
   int new_oload_champ;
-  struct badness_vector *new_oload_champ_bv;
   char *new_namespace;
 
   if (next_namespace_len != 0)
@@ -2906,9 +2898,6 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
   next_namespace_len +=
     cp_find_first_component (qualified_name + next_namespace_len);
 
-  /* Initialize these to values that can safely be xfree'd.  */
-  *oload_champ_bv = NULL;
-
   /* First, see if we have a deeper namespace we can search in.
      If we get a good match there, use it.  */
 
@@ -2934,7 +2923,6 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
      because this overload mechanism only gets called if there's a
      function symbol to start off with.)  */
 
-  old_cleanups = make_cleanup (xfree, *oload_champ_bv);
   new_namespace = (char *) alloca (namespace_len + 1);
   strncpy (new_namespace, qualified_name, namespace_len);
   new_namespace[namespace_len] = '\0';
@@ -2958,6 +2946,7 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				    new_oload_syms);
     }
 
+  badness_vector new_oload_champ_bv;
   new_oload_champ = find_oload_champ (args, new_oload_syms.size (),
 				      NULL, NULL, new_oload_syms.data (),
 				      &new_oload_champ_bv);
@@ -2974,22 +2963,18 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     {
       *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
-      *oload_champ_bv = new_oload_champ_bv;
-      do_cleanups (old_cleanups);
+      *oload_champ_bv = std::move (new_oload_champ_bv);
       return 1;
     }
   else if (searched_deeper)
     {
-      xfree (new_oload_champ_bv);
-      discard_cleanups (old_cleanups);
       return 0;
     }
   else
     {
       *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
-      *oload_champ_bv = new_oload_champ_bv;
-      do_cleanups (old_cleanups);
+      *oload_champ_bv = std::move (new_oload_champ_bv);
       return 0;
     }
 }
@@ -3003,20 +2988,18 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
    or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
 
    Return the index of the best match; store an indication of the
-   quality of the match in OLOAD_CHAMP_BV.
-
-   It is the caller's responsibility to free *OLOAD_CHAMP_BV.  */
+   quality of the match in OLOAD_CHAMP_BV.  */
 
 static int
 find_oload_champ (gdb::array_view<value *> args,
 		  int num_fns, struct fn_field *fns_ptr,
 		  const std::vector<xmethod_worker_up> *xm_worker_vec,
 		  struct symbol **oload_syms,
-		  struct badness_vector **oload_champ_bv)
+		  badness_vector *oload_champ_bv)
 {
   int ix;
   /* A measure of how good an overloaded instance is.  */
-  struct badness_vector *bv;
+  badness_vector bv;
   /* Index of best overloaded function.  */
   int oload_champ = -1;
   /* Current ambiguity state for overload resolution.  */
@@ -3029,8 +3012,6 @@ find_oload_champ (gdb::array_view<value *> args,
   gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) + (xm_worker_vec != NULL)
 	      == 1);
 
-  *oload_champ_bv = NULL;
-
   int fn_count = xm_worker_vec != NULL ? xm_worker_vec->size () : num_fns;
 
   /* Consider each candidate in turn.  */
@@ -3073,9 +3054,9 @@ find_oload_champ (gdb::array_view<value *> args,
       bv = rank_function (parm_types,
 			  args.slice (static_offset));
 
-      if (!*oload_champ_bv)
+      if (oload_champ_bv->empty ())
 	{
-	  *oload_champ_bv = bv;
+	  *oload_champ_bv = std::move (bv);
 	  oload_champ = 0;
 	}
       else /* See whether current candidate is better or worse than
@@ -3089,7 +3070,7 @@ find_oload_champ (gdb::array_view<value *> args,
 	    oload_ambiguous = 2;
 	    break;
 	  case 2:		/* New champion, record details.  */
-	    *oload_champ_bv = bv;
+	    *oload_champ_bv = std::move (bv);
 	    oload_ambiguous = 0;
 	    oload_champ = ix;
 	    break;
@@ -3116,7 +3097,7 @@ find_oload_champ (gdb::array_view<value *> args,
 	  for (jj = 0; jj < args.size () - static_offset; jj++)
 	    fprintf_filtered (gdb_stderr,
 			      "...Badness @ %d : %d\n", 
-			      jj, bv->rank[jj].rank);
+			      jj, bv[jj].rank);
 	  fprintf_filtered (gdb_stderr, "Overload resolution "
 			    "champion is %d, ambiguous? %d\n", 
 			    oload_champ, oload_ambiguous);
@@ -3141,7 +3122,7 @@ oload_method_static_p (struct fn_field *fns_ptr, int index)
 /* Check how good an overload match OLOAD_CHAMP_BV represents.  */
 
 static enum oload_classification
-classify_oload_match (struct badness_vector *oload_champ_bv,
+classify_oload_match (const badness_vector &oload_champ_bv,
 		      int nargs,
 		      int static_offset)
 {
@@ -3152,12 +3133,12 @@ classify_oload_match (struct badness_vector *oload_champ_bv,
     {
       /* If this conversion is as bad as INCOMPATIBLE_TYPE_BADNESS
          or worse return INCOMPATIBLE.  */
-      if (compare_ranks (oload_champ_bv->rank[ix],
+      if (compare_ranks (oload_champ_bv[ix],
                          INCOMPATIBLE_TYPE_BADNESS) <= 0)
 	return INCOMPATIBLE;	/* Truly mismatched types.  */
       /* Otherwise If this conversion is as bad as
          NS_POINTER_CONVERSION_BADNESS or worse return NON_STANDARD.  */
-      else if (compare_ranks (oload_champ_bv->rank[ix],
+      else if (compare_ranks (oload_champ_bv[ix],
                               NS_POINTER_CONVERSION_BADNESS) <= 0)
 	worst = NON_STANDARD;	/* Non-standard type conversions
 				   needed.  */
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 6/6] valops.c: Overload resolution code: Rename parameters/locals
  2018-10-15 15:11 [PATCH 0/6] Use gdb::array_view some more, plug leaks Pedro Alves
                   ` (4 preceding siblings ...)
  2018-10-15 15:16 ` [PATCH 4/6] C++ify badness_vector, fix leaks Pedro Alves
@ 2018-10-15 15:18 ` Pedro Alves
  5 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2018-10-15 15:18 UTC (permalink / raw)
  To: gdb-patches

While looking over this code, I thought the names of the parameters to
find_oload_champ and related functions and locals were a bit too
cryptic.  For example, FN_LIST holds methods, not free functions.
Free-functions are in OLOAD_SYMS.

This patch renames parameters/variables to the more obvious
methods/xmethods/functions instead.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* valops.c (find_method_list, value_find_oload_method_list)
	(find_overload_match, find_oload_champ): Rename parameters and
	locals.
---
 gdb/valops.c | 144 +++++++++++++++++++++++++++++------------------------------
 1 file changed, 72 insertions(+), 72 deletions(-)

diff --git a/gdb/valops.c b/gdb/valops.c
index ef2af09799..6f7939638a 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -68,9 +68,9 @@ static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 
 static int find_oload_champ (gdb::array_view<value *> args,
 			     size_t num_fns,
-			     fn_field *fns_ptr,
-			     xmethod_worker_up *xm_worker_vec,
-			     symbol **oload_syms,
+			     fn_field *methods,
+			     xmethod_worker_up *xmethods,
+			     symbol **functions,
 			     badness_vector *oload_champ_bv);
 
 static int oload_method_static_p (struct fn_field *, int);
@@ -2289,22 +2289,22 @@ value_union_variant (struct type *union_type, const gdb_byte *contents)
 }
 
 /* Search through the methods of an object (and its bases) to find a
-   specified method.  Return a reference to the fn_field list FN_LIST of
+   specified method.  Return a reference to the fn_field list METHODS of
    overloaded instances defined in the source language.  If available
    and matching, a vector of matching xmethods defined in extension
-   languages are also returned in XM_WORKER_VEC
+   languages are also returned in XMETHODS.
 
    Helper function for value_find_oload_list.
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is a string containing the method name.
    OFFSET is the offset within the value.
    TYPE is the assumed type of the object.
-   FN_LIST is the pointer to matching overloaded instances defined in
-      source language.  Since this is a recursive function, *FN_LIST
-      should be set to NULL when calling this function.
+   METHODS is a pointer to the matching overloaded instances defined
+      in the source language.  Since this is a recursive function,
+      *METHODS should be set to NULL when calling this function.
    NUM_FNS is the number of overloaded instances.  *NUM_FNS should be set to
       0 when calling this function.
-   XM_WORKER_VEC is the vector of matching xmethod workers.  *XM_WORKER_VEC
+   XMETHODS is the vector of matching xmethod workers.  *XMETHODS
       should also be set to NULL when calling this function.
    BASETYPE is set to the actual type of the subobject where the
       method is found.
@@ -2313,21 +2313,21 @@ value_union_variant (struct type *union_type, const gdb_byte *contents)
 static void
 find_method_list (struct value **argp, const char *method,
 		  LONGEST offset, struct type *type,
-		  gdb::array_view<fn_field> *fn_list,
-		  std::vector<xmethod_worker_up> *xm_worker_vec,
+		  gdb::array_view<fn_field> *methods,
+		  std::vector<xmethod_worker_up> *xmethods,
 		  struct type **basetype, LONGEST *boffset)
 {
   int i;
   struct fn_field *f = NULL;
 
-  gdb_assert (fn_list != NULL && xm_worker_vec != NULL);
+  gdb_assert (methods != NULL && xmethods != NULL);
   type = check_typedef (type);
 
   /* First check in object itself.
      This function is called recursively to search through base classes.
      If there is a source method match found at some stage, then we need not
      look for source methods in consequent recursive calls.  */
-  if (fn_list->empty ())
+  if (methods->empty ())
     {
       for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
 	{
@@ -2338,7 +2338,7 @@ find_method_list (struct value **argp, const char *method,
 	    {
 	      int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
 	      f = TYPE_FN_FIELDLIST1 (type, i);
-	      *fn_list = gdb::make_array_view (f, len);
+	      *methods = gdb::make_array_view (f, len);
 
 	      *basetype = type;
 	      *boffset = offset;
@@ -2358,7 +2358,7 @@ find_method_list (struct value **argp, const char *method,
      and hence there is no point restricting them with something like method
      hiding.  Moreover, if hiding is done for xmethods as well, then we will
      have to provide a mechanism to un-hide (like the 'using' construct).  */
-  get_matching_xmethod_workers (type, method, xm_worker_vec);
+  get_matching_xmethod_workers (type, method, xmethods);
 
   /* If source methods are not found in current class, look for them in the
      base classes.  We also have to go through the base classes to gather
@@ -2381,22 +2381,22 @@ find_method_list (struct value **argp, const char *method,
 	}
 
       find_method_list (argp, method, base_offset + offset,
-			TYPE_BASECLASS (type, i), fn_list,
-			xm_worker_vec, basetype, boffset);
+			TYPE_BASECLASS (type, i), methods,
+			xmethods, basetype, boffset);
     }
 }
 
 /* Return the list of overloaded methods of a specified name.  The methods
    could be those GDB finds in the binary, or xmethod.  Methods found in
-   the binary are returned in FN_LIST, and xmethods are returned in
-   XM_WORKER_VEC.
+   the binary are returned in METHODS, and xmethods are returned in
+   XMETHODS.
 
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is the method name.
    OFFSET is the offset within the value contents.
-   FN_LIST is the list of matching overloaded instances defined in
-      source language.
-   XM_WORKER_VEC is the vector of matching xmethod workers defined in
+   METHODS is the list of matching overloaded instances defined in
+      the source language.
+   XMETHODS is the vector of matching xmethod workers defined in
       extension languages.
    BASETYPE is set to the type of the base subobject that defines the
       method.
@@ -2405,8 +2405,8 @@ find_method_list (struct value **argp, const char *method,
 static void
 value_find_oload_method_list (struct value **argp, const char *method,
 			      LONGEST offset,
-			      gdb::array_view<fn_field> *fn_list,
-			      std::vector<xmethod_worker_up> *xm_worker_vec,
+			      gdb::array_view<fn_field> *methods,
+			      std::vector<xmethod_worker_up> *xmethods,
 			      struct type **basetype, LONGEST *boffset)
 {
   struct type *t;
@@ -2428,13 +2428,13 @@ value_find_oload_method_list (struct value **argp, const char *method,
     error (_("Attempt to extract a component of a "
 	     "value that is not a struct or union"));
 
-  gdb_assert (fn_list != NULL && xm_worker_vec != NULL);
+  gdb_assert (methods != NULL && xmethods != NULL);
 
   /* Clear the lists.  */
-  *fn_list = {};
-  xm_worker_vec->clear ();
+  *methods = {};
+  xmethods->clear ();
 
-  find_method_list (argp, method, 0, t, fn_list, xm_worker_vec,
+  find_method_list (argp, method, 0, t, methods, xmethods,
 		    basetype, boffset);
 }
 
@@ -2508,11 +2508,11 @@ find_overload_match (gdb::array_view<value *> args,
 
   struct value *temp = obj;
   /* For methods, the list of overloaded methods.  */
-  gdb::array_view<fn_field> fns_list;
+  gdb::array_view<fn_field> methods;
   /* For non-methods, the list of overloaded function symbols.  */
-  std::vector<symbol *> oload_syms;
-  /* For xmethods, the VEC of xmethod workers.  */
-  std::vector<xmethod_worker_up> xm_worker_vec;
+  std::vector<symbol *> functions;
+  /* For xmethods, the vector of xmethod workers.  */
+  std::vector<xmethod_worker_up> xmethods;
   struct type *basetype = NULL;
   LONGEST boffset;
 
@@ -2552,11 +2552,11 @@ find_overload_match (gdb::array_view<value *> args,
 	}
 
       /* Retrieve the list of methods with the name NAME.  */
-      value_find_oload_method_list (&temp, name, 0, &fns_list,
-				    &xm_worker_vec, &basetype, &boffset);
+      value_find_oload_method_list (&temp, name, 0, &methods,
+				    &xmethods, &basetype, &boffset);
       /* If this is a method only search, and no methods were found
          the search has failed.  */
-      if (method == METHOD && fns_list.empty () && xm_worker_vec.empty ())
+      if (method == METHOD && methods.empty () && xmethods.empty ())
 	error (_("Couldn't find method %s%s%s"),
 	       obj_type_name,
 	       (obj_type_name && *obj_type_name) ? "::" : "",
@@ -2564,27 +2564,27 @@ find_overload_match (gdb::array_view<value *> args,
       /* If we are dealing with stub method types, they should have
 	 been resolved by find_method_list via
 	 value_find_oload_method_list above.  */
-      if (!fns_list.empty ())
+      if (!methods.empty ())
 	{
-	  gdb_assert (TYPE_SELF_TYPE (fns_list[0].type) != NULL);
+	  gdb_assert (TYPE_SELF_TYPE (methods[0].type) != NULL);
 
 	  src_method_oload_champ
 	    = find_oload_champ (args,
-				fns_list.size (),
-				fns_list.data (), NULL, NULL,
+				methods.size (),
+				methods.data (), NULL, NULL,
 				&src_method_badness);
 
 	  src_method_match_quality = classify_oload_match
 	    (src_method_badness, args.size (),
-	     oload_method_static_p (fns_list.data (), src_method_oload_champ));
+	     oload_method_static_p (methods.data (), src_method_oload_champ));
 	}
 
-      if (!xm_worker_vec.empty ())
+      if (!xmethods.empty ())
 	{
 	  ext_method_oload_champ
 	    = find_oload_champ (args,
-				xm_worker_vec.size (),
-				NULL, xm_worker_vec.data (), NULL,
+				xmethods.size (),
+				NULL, xmethods.data (), NULL,
 				&ext_method_badness);
 	  ext_method_match_quality = classify_oload_match (ext_method_badness,
 							   args.size (), 0);
@@ -2702,7 +2702,7 @@ find_overload_match (gdb::array_view<value *> args,
       func_oload_champ = find_oload_champ_namespace (args,
                                                      func_name,
                                                      qualified_name,
-                                                     &oload_syms,
+                                                     &functions,
                                                      &func_badness,
                                                      no_adl);
 
@@ -2784,29 +2784,29 @@ find_overload_match (gdb::array_view<value *> args,
     }
 
   if (staticp != NULL)
-    *staticp = oload_method_static_p (fns_list.data (), method_oload_champ);
+    *staticp = oload_method_static_p (methods.data (), method_oload_champ);
 
   if (method_oload_champ >= 0)
     {
       if (src_method_oload_champ >= 0)
 	{
-	  if (TYPE_FN_FIELD_VIRTUAL_P (fns_list, method_oload_champ)
+	  if (TYPE_FN_FIELD_VIRTUAL_P (methods, method_oload_champ)
 	      && noside != EVAL_AVOID_SIDE_EFFECTS)
 	    {
-	      *valp = value_virtual_fn_field (&temp, fns_list.data (),
+	      *valp = value_virtual_fn_field (&temp, methods.data (),
 					      method_oload_champ, basetype,
 					      boffset);
 	    }
 	  else
-	    *valp = value_fn_field (&temp, fns_list.data (),
+	    *valp = value_fn_field (&temp, methods.data (),
 				    method_oload_champ, basetype, boffset);
 	}
       else
 	*valp = value_from_xmethod
-	  (std::move (xm_worker_vec[ext_method_oload_champ]));
+	  (std::move (xmethods[ext_method_oload_champ]));
     }
   else
-    *symp = oload_syms[func_oload_champ];
+    *symp = functions[func_oload_champ];
 
   if (objp)
     {
@@ -2978,12 +2978,12 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 }
 
 /* Look for a function to take ARGS.  Find the best match from among
-   the overloaded methods or functions given by FNS_PTR or OLOAD_SYMS
-   or XM_WORKER_VEC, respectively.  One, and only one of FNS_PTR,
-   OLOAD_SYMS and XM_WORKER_VEC can be non-NULL.
+   the overloaded methods or functions given by METHODS or FUNCTIONS
+   or XMETHODS, respectively.  One, and only one of METHODS, FUNCTIONS
+   and XMETHODS can be non-NULL.
 
-   NUM_FNS is the length of the array pointed at by FNS_PTR,
-   OLOAD_SYMS of XM_WORKER_VEC, whichever is non-NULL.
+   NUM_FNS is the length of the array pointed at by METHODS, FUNCTIONS
+   or XMETHODS, whichever is non-NULL.
 
    Return the index of the best match; store an indication of the
    quality of the match in OLOAD_CHAMP_BV.  */
@@ -2991,9 +2991,9 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 static int
 find_oload_champ (gdb::array_view<value *> args,
 		  size_t num_fns,
-		  fn_field *fns_ptr,
-		  xmethod_worker_up *xm_worker_vec,
-		  symbol **oload_syms,
+		  fn_field *methods,
+		  xmethod_worker_up *xmethods,
+		  symbol **functions,
 		  badness_vector *oload_champ_bv)
 {
   /* A measure of how good an overloaded instance is.  */
@@ -3007,7 +3007,7 @@ find_oload_champ (gdb::array_view<value *> args,
   /* A champion can be found among methods alone, or among functions
      alone, or in xmethods alone, but not in more than one of these
      groups.  */
-  gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) + (xm_worker_vec != NULL)
+  gdb_assert ((methods != NULL) + (functions != NULL) + (xmethods != NULL)
 	      == 1);
 
   /* Consider each candidate in turn.  */
@@ -3017,26 +3017,26 @@ find_oload_champ (gdb::array_view<value *> args,
       int static_offset = 0;
       std::vector<type *> parm_types;
 
-      if (xm_worker_vec != NULL)
-	parm_types = xm_worker_vec[ix]->get_arg_types ();
+      if (xmethods != NULL)
+	parm_types = xmethods[ix]->get_arg_types ();
       else
 	{
 	  size_t nparms;
 
-	  if (fns_ptr != NULL)
+	  if (methods != NULL)
 	    {
-	      nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
-	      static_offset = oload_method_static_p (fns_ptr, ix);
+	      nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (methods, ix));
+	      static_offset = oload_method_static_p (methods, ix);
 	    }
 	  else
-	    nparms = TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
+	    nparms = TYPE_NFIELDS (SYMBOL_TYPE (functions[ix]));
 
 	  parm_types.reserve (nparms);
 	  for (jj = 0; jj < nparms; jj++)
 	    {
-	      type *t = (fns_ptr != NULL
-			 ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
-			 : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
+	      type *t = (methods != NULL
+			 ? (TYPE_FN_FIELD_ARGS (methods, ix)[jj].type)
+			 : TYPE_FIELD_TYPE (SYMBOL_TYPE (functions[ix]),
 					    jj));
 	      parm_types.push_back (t);
 	    }
@@ -3073,11 +3073,11 @@ find_oload_champ (gdb::array_view<value *> args,
 	  }
       if (overload_debug)
 	{
-	  if (fns_ptr != NULL)
+	  if (methods != NULL)
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded method instance %s, # of parms %d\n",
-			      fns_ptr[ix].physname, (int) parm_types.size ());
-	  else if (xm_worker_vec != NULL)
+			      methods[ix].physname, (int) parm_types.size ());
+	  else if (xmethods != NULL)
 	    fprintf_filtered (gdb_stderr,
 			      "Xmethod worker, # of parms %d\n",
 			      (int) parm_types.size ());
@@ -3085,7 +3085,7 @@ find_oload_champ (gdb::array_view<value *> args,
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded function instance "
 			      "%s # of parms %d\n",
-			      SYMBOL_DEMANGLED_NAME (oload_syms[ix]), 
+			      SYMBOL_DEMANGLED_NAME (functions[ix]),
 			      (int) parm_types.size ());
 	  for (jj = 0; jj < args.size () - static_offset; jj++)
 	    fprintf_filtered (gdb_stderr,
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends
  2018-10-15 15:11 ` [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends Pedro Alves
@ 2018-10-17  1:45   ` Simon Marchi
  2018-11-21 12:39     ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2018-10-17  1:45 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 2018-10-15 11:11 a.m., Pedro Alves wrote:
> This replaces a few uses of pointer+length with gdb::array_view, in
> call_function_by_hand and related code.
> 
> Unfortunately, due to -Wnarrowing, there are places where we can't
> brace-initialize an gdb::array_view without an ugly-ish cast.  To
> avoid the cast, this patch introduces a gdb::make_array_view function.
> Unit tests included.
> 
> This patch in isolation may not look so interesting, due to
> gdb::make_array_view uses, but I think it's still worth it.  Some of
> the gdb::make_array_view calls disappear down the series, and others
> could be eliminated with more (non-trivial) gdb::array_view
> detangling/conversion (e.g. code around eval_call).  See this as a "we
> have to start somewhere" patch.

LGTM with two comments:

- The function doc in infcall.h should be updated
- This patch doesn't build for me, probably just one forgotten spot:

  CXX    spu-tdep.o
/home/simark/src/binutils-gdb/gdb/spu-tdep.c: In function ‘void flush_ea_cache()’:
/home/simark/src/binutils-gdb/gdb/spu-tdep.c:2043:69: error: could not convert ‘0’ from ‘int’ to ‘gdb::array_view<value*>’
       call_function_by_hand (value_from_pointer (type, addr), NULL, 0, NULL);
                                                                     ^

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/6] invoke_xmethod & array_view
  2018-10-15 15:11 ` [PATCH 2/6] invoke_xmethod & array_view Pedro Alves
@ 2018-10-17 16:21   ` Simon Marchi
  2018-11-21 12:47     ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2018-10-17 16:21 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 2018-10-15 11:11 a.m., Pedro Alves wrote:
> This replaces more pointer+length with gdb::array_view.  This time,
> around invoke_xmethod, and then propagating the fallout around, which
> inevitably leads to the overload resolution code.
> 
> There are several places in the code that want to grab a slice of an
> array, by advanting the array pointer, and decreasing the length

"advanting"

> pointer.  This patch introduces a pair of new
> gdb::array_view::slice(...) methods to make that convenient and clear.
> Unit test included.

Cool!

Just some minor comments.

I noticed some lines > 80 columns:

$ git show | grep ^\+ | tr '\t' '        ' | egrep '.{81}'
+      return call_xmethod (argvec[0], gdb::make_array_view (argvec + 1, nargs));
+value_user_defined_op (struct value **argp, gdb::array_view<value *> args, char *name,
+      && classify_oload_match (new_oload_champ_bv, args.size (), 0) == STANDARD)


> diff --git a/gdb/common/array-view.h b/gdb/common/array-view.h
> index 45d1a4720e..679d2e95c7 100644
> --- a/gdb/common/array-view.h
> +++ b/gdb/common/array-view.h
> @@ -169,6 +169,17 @@ public:
>    constexpr size_type size () const noexcept { return m_size; }
>    constexpr bool empty () const noexcept { return m_size == 0; }
>  
> +  /* Slice an array view.  */
> +
> +  /* Return a new array view over SIZE elements starting at START.  */
> +  constexpr array_view<T> slice (size_type start, size_t size) const noexcept
> +  { return {m_array + start, size}; }

I'm sure there's a logic for using size_type for one parameter and size_t for the other
(instead of size_type for both), but what is it?

> +
> +  /* Return a new array view over all the elements after START,
> +     inclusive.  */
> +  constexpr array_view<T> slice (size_type start) const noexcept
> +  { return {m_array + start, size () - start}; }

It would perhaps be good to have some asserts (that are only there in development
mode, maybe) to make sure we don't do stupid things, like take a slice
past the end of the array, things like that.  A bit like those asserts enabled by
__GLIBCXX_DEBUG.

> diff --git a/gdb/extension.h b/gdb/extension.h
> index 0c8c4ee934..4716d6f360 100644
> --- a/gdb/extension.h
> +++ b/gdb/extension.h
> @@ -22,6 +22,7 @@
>  
>  #include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc.  */
>  #include "common/vec.h"
> +#include "common/array-view.h"
>  
>  struct breakpoint;
>  struct command_line;
> @@ -186,38 +187,35 @@ struct xmethod_worker
>    virtual ~xmethod_worker () = default;
>  
>    /* Invoke the xmethod encapsulated in this worker and return the result.
> -     The method is invoked on OBJ with arguments in the ARGS array.  NARGS is
> -     the length of the this array.  */
> +     The method is invoked on OBJ with arguments in the ARGS array.  */
>  
> -  virtual value *invoke (value *obj, value **args, int nargs) = 0;
> +  virtual value *invoke (value *obj, gdb::array_view<value *> args) = 0;
>  
>    /* Return the arg types of the xmethod encapsulated in this worker.
> -     An array of arg types is returned.  The length of the array is returned in
> -     NARGS.  The type of the 'this' object is returned as the first element of
> -     array.  */
> +     The type of the 'this' object is returned as the first element of
> +     the vector.  */
>  
> -  type **get_arg_types (int *nargs);
> +  std::vector<type *> get_arg_types ();
>  
>    /* Return the type of the result of the xmethod encapsulated in this worker.
> -     OBJECT, ARGS, NARGS are the same as for invoke.  */
> +     OBJECT and ARGS are the same as for invoke.  */
>  
> -  type *get_result_type (value *object, value **args, int nargs);
> +  type *get_result_type (value *object, gdb::array_view<value *> args);
>  
>  private:
>  
> -  /* Return the types of the arguments the method takes.  The number of
> -     arguments is returned in NARGS, and their types are returned in the array
> -     ARGTYPES.  */
> +  /* Return the types of the arguments the method takes.  The types
> +     are returned in TYPE_ARGS, one per argument.  */
>  
>    virtual enum ext_lang_rc do_get_arg_types
> -    (int *nargs, struct type ***arg_types) = 0;
> +    (std::vector<type *> &type_args) = 0;

Could you change this to be a pointer to the std::vector?

https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Avoid_non-const_reference_parameters.2C_use_pointers_instead

> @@ -312,19 +312,19 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *oper,
>     function, otherwise return NULL.  */
>  
>  static struct value *
> -value_user_defined_op (struct value **argp, struct value **args, char *name,
> -                       int *static_memfuncp, int nargs, enum noside noside)
> +value_user_defined_op (struct value **argp, gdb::array_view<value *> args, char *name,
> +		       int *static_memfuncp, enum noside noside)
>  {
>    struct value *result = NULL;
>  
>    if (current_language->la_language == language_cplus)
>      {
> -      result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp,
> +      result = value_user_defined_cpp_op (args, name, static_memfuncp,
>  					  noside);
>      }

Maybe remove the extra braces, while touching this.

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/6] Eliminate make_symbol_overload_list-related globals & cleanup
  2018-10-15 15:11 ` [PATCH 3/6] Eliminate make_symbol_overload_list-related globals & cleanup Pedro Alves
@ 2018-10-17 17:25   ` Simon Marchi
  2018-11-21 12:47     ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2018-10-17 17:25 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 2018-10-15 11:11 a.m., Pedro Alves wrote:
> This gets rid of a few globals and a cleanup.
> 
> make_symbol_overload_list & friends currently maintain a global
> open-coded vector.  Reimplement that with a std::vector, trickled down
> through the functions.  Rename a few functions from "make_" to "add_"
> for clarity.

LGTM, my only comment would be to avoid non-const passing by reference, as in
the previous patch.

Simon


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/6] C++ify badness_vector, fix leaks
  2018-10-15 15:16 ` [PATCH 4/6] C++ify badness_vector, fix leaks Pedro Alves
@ 2018-10-17 17:44   ` Simon Marchi
  2018-11-21 12:47     ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2018-10-17 17:44 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

LGTM, just a tiny comment:

On 2018-10-15 11:11 a.m., Pedro Alves wrote:
> @@ -2848,7 +2842,7 @@ find_overload_match (gdb::array_view<value *> args,
>     contained in QUALIFIED_NAME until it either finds a good match or
>     runs out of namespaces.  It stores the overloaded functions in
>     *OLOAD_SYMS, and the badness vector in *OLOAD_CHAMP_BV.  The
> -   calling function is responsible for freeing *OLOAD_SYMS and
> +   calling function is responsible for clearing *OLOAD_SYMS and
>     *OLOAD_CHAMP_BV.  If NO_ADL, argument dependent lookup is not 
>     performned.  */

The previous comment meant that the caller was responsible to free the data
after this function is called.  From what I understand, the new comment means
the caller is responsible to pass empty vectors as inputs, is that right?  If
so, it would be clearer to say "the calling function is responsible for passing
empty vectors for *OLOAD_SYMS and *OLOAD_CHAMP_BV".

I know the opposite wouldn't really make sense (asking the caller to clear the
vector after the call), but like this it sounds ambiguous.

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/6] valops.c: Some more gdb::array_view
  2018-10-15 15:11 ` [PATCH 5/6] valops.c: Some more gdb::array_view Pedro Alves
@ 2018-10-17 18:03   ` Simon Marchi
  2018-11-21 12:48     ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2018-10-17 18:03 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 2018-10-15 11:11 a.m., Pedro Alves wrote:
> This commit replaces some more use of pointer+length pairs in the
> overload resolution code with gdb::array_view.
> 
> find_oload_champ's interface is simplified/normalized: the xmethods
> parameter is converted from std::vector to array pointer, and then the
> num_fns parameter is always passed in, no matter the array which is
> non-NULL.  I tweaked the formatting of callers a little bit here and
> there so that the 3 optional parameters are all in the same line.  (I
> tried making the 3 optional array parameters be array_views, but the
> resulting code didn't look as nice.)

I don't really understand what's happening in that code, but it looks to me
like the behavior is kept, which is good.

> @@ -2572,23 +2564,28 @@ find_overload_match (gdb::array_view<value *> args,
>        /* If we are dealing with stub method types, they should have
>  	 been resolved by find_method_list via
>  	 value_find_oload_method_list above.  */
> -      if (fns_ptr)
> +      if (!fns_list.empty ())
>  	{
> -	  gdb_assert (TYPE_SELF_TYPE (fns_ptr[0].type) != NULL);
> +	  gdb_assert (TYPE_SELF_TYPE (fns_list[0].type) != NULL);
>  
> -	  src_method_oload_champ = find_oload_champ (args,
> -						     num_fns, fns_ptr, NULL,
> -						     NULL, &src_method_badness);
> +	  src_method_oload_champ
> +	    = find_oload_champ (args,
> +				fns_list.size (),
> +				fns_list.data (), NULL, NULL,
> +				&src_method_badness);
>  
>  	  src_method_match_quality = classify_oload_match
>  	    (src_method_badness, args.size (),
> -	     oload_method_static_p (fns_ptr, src_method_oload_champ));
> +	     oload_method_static_p (fns_list.data (), src_method_oload_champ));
>  	}
>  
>        if (!xm_worker_vec.empty ())
>  	{
> -	  ext_method_oload_champ = find_oload_champ (args, 0, NULL, &xm_worker_vec,
> -						     NULL, &ext_method_badness);
> +	  ext_method_oload_champ
> +	    = find_oload_champ (args,
> +				xm_worker_vec.size (),
> +				NULL, xm_worker_vec.data (), NULL,
> +				&ext_method_badness);

The previous code passed a size of 0... was it an error?

> @@ -2984,20 +2982,20 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
>     or XM_WORKER_VEC, respectively.  One, and only one of FNS_PTR,
>     OLOAD_SYMS and XM_WORKER_VEC can be non-NULL.
>  
> -   If XM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
> -   or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
> +   NUM_FNS is the length of the array pointed at by FNS_PTR,
> +   OLOAD_SYMS of XM_WORKER_VEC, whichever is non-NULL.

of -> or

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends
  2018-10-17  1:45   ` Simon Marchi
@ 2018-11-21 12:39     ` Pedro Alves
  0 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2018-11-21 12:39 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 10/17/2018 02:45 AM, Simon Marchi wrote:
> On 2018-10-15 11:11 a.m., Pedro Alves wrote:
>> This replaces a few uses of pointer+length with gdb::array_view, in
>> call_function_by_hand and related code.
>>
>> Unfortunately, due to -Wnarrowing, there are places where we can't
>> brace-initialize an gdb::array_view without an ugly-ish cast.  To
>> avoid the cast, this patch introduces a gdb::make_array_view function.
>> Unit tests included.
>>
>> This patch in isolation may not look so interesting, due to
>> gdb::make_array_view uses, but I think it's still worth it.  Some of
>> the gdb::make_array_view calls disappear down the series, and others
>> could be eliminated with more (non-trivial) gdb::array_view
>> detangling/conversion (e.g. code around eval_call).  See this as a "we
>> have to start somewhere" patch.
> 
> LGTM with two comments:
> 
> - The function doc in infcall.h should be updated
> - This patch doesn't build for me, probably just one forgotten spot:
> 
>   CXX    spu-tdep.o
> /home/simark/src/binutils-gdb/gdb/spu-tdep.c: In function ‘void flush_ea_cache()’:
> /home/simark/src/binutils-gdb/gdb/spu-tdep.c:2043:69: error: could not convert ‘0’ from ‘int’ to ‘gdb::array_view<value*>’
>        call_function_by_hand (value_from_pointer (type, addr), NULL, 0, NULL);
Whoops, yes.  Fixed now, and merged, as below.

From e71585ffe2e1394858f0fcf809e86f1b324fe4e6 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 21 Nov 2018 11:55:11 +0000
Subject: [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends

This replaces a few uses of pointer+length with gdb::array_view, in
call_function_by_hand and related code.

Unfortunately, due to -Wnarrowing, there are places where we can't
brace-initialize an gdb::array_view without an ugly-ish cast.  To
avoid the cast, this patch introduces a gdb::make_array_view function.
Unit tests included.

This patch in isolation may not look so interesting, due to
gdb::make_array_view uses, but I think it's still worth it.  Some of
the gdb::make_array_view calls disappear down the series, and others
could be eliminated with more (non-trivial) gdb::array_view
detangling/conversion (e.g. code around eval_call).  See this as a "we
have to start somewhere" patch.

gdb/ChangeLog:
2018-11-21  Pedro Alves  <palves@redhat.com>

	* ada-lang.c (ada_evaluate_subexp): Adjust to pass an array_view.
	* common/array-view.h (make_array_view): New.
	* compile/compile-object-run.c (compile_object_run): Adjust to
	pass an array_view.
	* elfread.c (elf_gnu_ifunc_resolve_addr): Adjust.
	* eval.c (eval_call): Adjust to pass an array_view.
	(evaluate_subexp_standard): Adjust to pass an array_view.
	* gcore.c (call_target_sbrk): Adjust to pass an array_view.
	* guile/scm-value.c (gdbscm_value_call): Likewise.
	* infcall.c (push_dummy_code): Replace pointer + size parameters
	with an array_view parameter.
	(call_function_by_hand, call_function_by_hand_dummy): Likewise and
	adjust.
	* infcall.h: Include "common/array-view.h".
	(call_function_by_hand, call_function_by_hand_dummy): Replace
	pointer + size parameters with an array_view parameter.
	* linux-fork.c (inferior_call_waitpid): Adjust to use array_view.
	* linux-tdep.c (linux_infcall_mmap): Likewise.
	* objc-lang.c (lookup_objc_class, lookup_child_selector)
	(value_nsstring, print_object_command): Likewise.
	* python/py-value.c (valpy_call): Likewise.
	* rust-lang.c (rust_evaluate_funcall): Likewise.
	* spu-tdep.c (flush_ea_cache): Likewise.
	* valarith.c (value_x_binop, value_x_unop): Likewise.
	* valops.c (value_allocate_space_in_inferior): Likewise.
	* unittests/array-view-selftests.c (run_tests): Add
	gdb::make_array_view test.
---
 gdb/ChangeLog                        | 30 ++++++++++++++++++++++++++
 gdb/ada-lang.c                       |  4 +++-
 gdb/common/array-view.h              | 42 ++++++++++++++++++++++++++++++++++++
 gdb/compile/compile-object-run.c     |  4 ++--
 gdb/elfread.c                        |  2 +-
 gdb/eval.c                           | 18 ++++++++--------
 gdb/gcore.c                          |  2 +-
 gdb/guile/scm-value.c                |  4 ++--
 gdb/infcall.c                        | 29 +++++++++++++------------
 gdb/infcall.h                        | 15 ++++++-------
 gdb/linux-fork.c                     |  7 +++---
 gdb/linux-tdep.c                     |  4 ++--
 gdb/objc-lang.c                      | 13 ++++++-----
 gdb/python/py-value.c                |  6 +++---
 gdb/rust-lang.c                      |  2 +-
 gdb/spu-tdep.c                       |  2 +-
 gdb/unittests/array-view-selftests.c | 13 +++++++++++
 gdb/valarith.c                       |  7 +++---
 gdb/valops.c                         |  2 +-
 19 files changed, 146 insertions(+), 60 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ddd93f246b..e315f34dc1 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,33 @@
+2018-11-21  Pedro Alves  <palves@redhat.com>
+
+	* ada-lang.c (ada_evaluate_subexp): Adjust to pass an array_view.
+	* common/array-view.h (make_array_view): New.
+	* compile/compile-object-run.c (compile_object_run): Adjust to
+	pass an array_view.
+	* elfread.c (elf_gnu_ifunc_resolve_addr): Adjust.
+	* eval.c (eval_call): Adjust to pass an array_view.
+	(evaluate_subexp_standard): Adjust to pass an array_view.
+	* gcore.c (call_target_sbrk): Adjust to pass an array_view.
+	* guile/scm-value.c (gdbscm_value_call): Likewise.
+	* infcall.c (push_dummy_code): Replace pointer + size parameters
+	with an array_view parameter.
+	(call_function_by_hand, call_function_by_hand_dummy): Likewise and
+	adjust.
+	* infcall.h: Include "common/array-view.h".
+	(call_function_by_hand, call_function_by_hand_dummy): Replace
+	pointer + size parameters with an array_view parameter.
+	* linux-fork.c (inferior_call_waitpid): Adjust to use array_view.
+	* linux-tdep.c (linux_infcall_mmap): Likewise.
+	* objc-lang.c (lookup_objc_class, lookup_child_selector)
+	(value_nsstring, print_object_command): Likewise.
+	* python/py-value.c (valpy_call): Likewise.
+	* rust-lang.c (rust_evaluate_funcall): Likewise.
+	* spu-tdep.c (flush_ea_cache): Likewise.
+	* valarith.c (value_x_binop, value_x_unop): Likewise.
+	* valops.c (value_allocate_space_in_inferior): Likewise.
+	* unittests/array-view-selftests.c (run_tests): Add
+	gdb::make_array_view test.
+
 2018-11-20  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* cli-out.c (cli_ui_out::do_field_int): Use string_printf rather
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 8967cf17e3..95bf6703ac 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10928,7 +10928,9 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 		error_call_unknown_return_type (NULL);
 	      return allocate_value (TYPE_TARGET_TYPE (type));
 	    }
-	  return call_function_by_hand (argvec[0], NULL, nargs, argvec + 1);
+	  return call_function_by_hand (argvec[0], NULL,
+					gdb::make_array_view (argvec + 1,
+							      nargs));
 	case TYPE_CODE_INTERNAL_FUNCTION:
 	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	    /* We don't know anything about what the internal
diff --git a/gdb/common/array-view.h b/gdb/common/array-view.h
index 319ea99468..9c5fa2a971 100644
--- a/gdb/common/array-view.h
+++ b/gdb/common/array-view.h
@@ -201,6 +201,48 @@ operator!= (const gdb::array_view<T> &lhs, const gdb::array_view<T> &rhs)
   return !(lhs == rhs);
 }
 
+/* Create an array view from a pointer to an array and an element
+   count.
+
+   This is useful as alternative to constructing an array_view using
+   brace initialization when the size variable you have handy is of
+   signed type, since otherwise without an explicit cast the code
+   would be ill-formed.
+
+   For example, with:
+
+     extern void foo (int, int, gdb::array_view<value *>);
+
+     value *args[2];
+     int nargs;
+     foo (1, 2, {values, nargs});
+
+   You'd get:
+
+     source.c:10: error: narrowing conversion of ‘nargs’ from ‘int’ to
+     ‘size_t {aka long unsigned int}’ inside { } [-Werror=narrowing]
+
+   You could fix it by writing the somewhat distracting explicit cast:
+
+     foo (1, 2, {values, (size_t) nargs});
+
+   Or by instantiating an array_view explicitly:
+
+     foo (1, 2, gdb::array_view<value *>(values, nargs));
+
+   Or, better, using make_array_view, which has the advantage of
+   inferring the arrav_view element's type:
+
+     foo (1, 2, gdb::make_array_view (values, nargs));
+*/
+
+template<typename U>
+constexpr inline array_view<U>
+make_array_view (U *array, size_t size) noexcept
+{
+  return {array, size};
+}
+
 } /* namespace gdb */
 
 #endif
diff --git a/gdb/compile/compile-object-run.c b/gdb/compile/compile-object-run.c
index f3ec932365..e891e77fba 100644
--- a/gdb/compile/compile-object-run.c
+++ b/gdb/compile/compile-object-run.c
@@ -170,8 +170,8 @@ compile_object_run (struct compile_module *module)
 	  ++current_arg;
 	}
       gdb_assert (current_arg == TYPE_NFIELDS (func_type));
-      call_function_by_hand_dummy (func_val,
-				   NULL, TYPE_NFIELDS (func_type), vargs,
+      auto args = gdb::make_array_view (vargs, TYPE_NFIELDS (func_type));
+      call_function_by_hand_dummy (func_val, NULL, args,
 				   do_module_cleanup, data);
     }
   CATCH (ex, RETURN_MASK_ERROR)
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 9f1fa2bec4..71e6fcca6e 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -904,7 +904,7 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   target_auxv_search (current_top_target (), AT_HWCAP, &hwcap);
   hwcap_val = value_from_longest (builtin_type (gdbarch)
 				  ->builtin_unsigned_long, hwcap);
-  address_val = call_function_by_hand (function, NULL, 1, &hwcap_val);
+  address_val = call_function_by_hand (function, NULL, hwcap_val);
   address = value_as_address (address_val);
   address = gdbarch_convert_from_func_ptr_addr (gdbarch, address, current_top_target ());
   address = gdbarch_addr_bits_remove (gdbarch, address);
diff --git a/gdb/eval.c b/gdb/eval.c
index 047aba59ae..6eb210d109 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -830,7 +830,7 @@ eval_call (expression *exp, enum noside noside,
       return call_xmethod (argvec[0], nargs, argvec + 1);
     default:
       return call_function_by_hand (argvec[0], default_return_type,
-				    nargs, argvec + 1);
+				    gdb::make_array_view (argvec + 1, nargs));
     }
 }
 
@@ -1728,12 +1728,12 @@ evaluate_subexp_standard (struct type *expect_type,
 	argvec[3] = value_from_longest (long_type, selector);
 	argvec[4] = 0;
 
-	ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	if (gnu_runtime)
 	  {
 	    /* Function objc_msg_lookup returns a pointer.  */
 	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	    ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	  }
 	if (value_as_long (ret) == 0)
 	  error (_("Target does not respond to this message selector."));
@@ -1750,11 +1750,11 @@ evaluate_subexp_standard (struct type *expect_type,
 	argvec[3] = value_from_longest (long_type, selector);
 	argvec[4] = 0;
 
-	ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	if (gnu_runtime)
 	  {
 	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
+	    ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
 	  }
 
 	/* ret should now be the selector.  */
@@ -1890,17 +1890,17 @@ evaluate_subexp_standard (struct type *expect_type,
 	  argvec[tem + 3] = evaluate_subexp_with_coercion (exp, pos, noside);
 	argvec[tem + 3] = 0;
 
+	auto call_args = gdb::make_array_view (argvec + 1, nargs + 2);
+
 	if (gnu_runtime && (method != NULL))
 	  {
 	    /* Function objc_msg_lookup returns a pointer.  */
 	    deprecated_set_value_type (argvec[0],
 				       lookup_pointer_type (lookup_function_type (value_type (argvec[0]))));
-	    argvec[0]
-	      = call_function_by_hand (argvec[0], NULL, nargs + 2, argvec + 1);
+	    argvec[0] = call_function_by_hand (argvec[0], NULL, call_args);
 	  }
 
-	ret = call_function_by_hand (argvec[0], NULL, nargs + 2, argvec + 1);
-	return ret;
+	return call_function_by_hand (argvec[0], NULL, call_args);
       }
       break;
 
diff --git a/gdb/gcore.c b/gdb/gcore.c
index fbebb6af18..24810a7dee 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -300,7 +300,7 @@ call_target_sbrk (int sbrk_arg)
   target_sbrk_arg = value_from_longest (builtin_type (gdbarch)->builtin_int, 
 					sbrk_arg);
   gdb_assert (target_sbrk_arg);
-  ret = call_function_by_hand (sbrk_fn, NULL, 1, &target_sbrk_arg);
+  ret = call_function_by_hand (sbrk_fn, NULL, target_sbrk_arg);
   if (ret == NULL)
     return (bfd_vma) 0;
 
diff --git a/gdb/guile/scm-value.c b/gdb/guile/scm-value.c
index ca0c075f5c..42afd609f6 100644
--- a/gdb/guile/scm-value.c
+++ b/gdb/guile/scm-value.c
@@ -730,8 +730,8 @@ gdbscm_value_call (SCM self, SCM args)
     {
       scoped_value_mark free_values;
 
-      value *return_value = call_function_by_hand (function, NULL,
-						   args_count, vargs);
+      auto av = gdb::make_array_view (vargs, args_count);
+      value *return_value = call_function_by_hand (function, NULL, av);
       return vlscm_scm_from_value (return_value);
     });
 }
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 1b1e7daf7a..82595a4796 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -334,7 +334,7 @@ find_function_addr (struct value *function,
 static CORE_ADDR
 push_dummy_code (struct gdbarch *gdbarch,
 		 CORE_ADDR sp, CORE_ADDR funaddr,
-		 struct value **args, int nargs,
+		 gdb::array_view<value *> args,
 		 struct type *value_type,
 		 CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
 		 struct regcache *regcache)
@@ -342,7 +342,8 @@ push_dummy_code (struct gdbarch *gdbarch,
   gdb_assert (gdbarch_push_dummy_code_p (gdbarch));
 
   return gdbarch_push_dummy_code (gdbarch, sp, funaddr,
-				  args, nargs, value_type, real_pc, bp_addr,
+				  args.data (), args.size (),
+				  value_type, real_pc, bp_addr,
 				  regcache);
 }
 
@@ -686,10 +687,10 @@ cleanup_delete_std_terminate_breakpoint (void *ignore)
 struct value *
 call_function_by_hand (struct value *function,
 		       type *default_return_type,
-		       int nargs, struct value **args)
+		       gdb::array_view<value *> args)
 {
   return call_function_by_hand_dummy (function, default_return_type,
-				      nargs, args, NULL, NULL);
+				      args, NULL, NULL);
 }
 
 /* All this stuff with a dummy frame may seem unnecessarily complicated
@@ -713,7 +714,7 @@ call_function_by_hand (struct value *function,
 struct value *
 call_function_by_hand_dummy (struct value *function,
 			     type *default_return_type,
-			     int nargs, struct value **args,
+			     gdb::array_view<value *> args,
 			     dummy_frame_dtor_ftype *dummy_dtor,
 			     void *dummy_dtor_data)
 {
@@ -912,7 +913,7 @@ call_function_by_hand_dummy (struct value *function,
 	/* Be careful BP_ADDR is in inferior PC encoding while
 	   BP_ADDR_AS_ADDRESS is a plain memory address.  */
 
-	sp = push_dummy_code (gdbarch, sp, funaddr, args, nargs,
+	sp = push_dummy_code (gdbarch, sp, funaddr, args,
 			      target_values_type, &real_pc, &bp_addr,
 			      get_current_regcache ());
 
@@ -953,14 +954,14 @@ call_function_by_hand_dummy (struct value *function,
       internal_error (__FILE__, __LINE__, _("bad switch"));
     }
 
-  if (nargs < TYPE_NFIELDS (ftype))
+  if (args.size () < TYPE_NFIELDS (ftype))
     error (_("Too few arguments in function call."));
 
-  for (int i = nargs - 1; i >= 0; i--)
+  for (int i = args.size () - 1; i >= 0; i--)
     {
       int prototyped;
       struct type *param_type;
-	
+
       /* FIXME drow/2002-05-31: Should just always mark methods as
 	 prototyped.  Can we respect TYPE_VARARGS?  Probably not.  */
       if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
@@ -1041,19 +1042,19 @@ call_function_by_hand_dummy (struct value *function,
   if (return_method == return_method_hidden_param)
     {
       /* Add the new argument to the front of the argument list.  */
+      new_args.reserve (args.size ());
       new_args.push_back
 	(value_from_pointer (lookup_pointer_type (values_type), struct_addr));
-      std::copy (&args[0], &args[nargs], std::back_inserter (new_args));
-      args = new_args.data ();
-      nargs++;
+      new_args.insert (new_args.end (), args.begin (), args.end ());
+      args = new_args;
     }
 
   /* Create the dummy stack frame.  Pass in the call dummy address as,
      presumably, the ABI code knows where, in the call dummy, the
      return address should be pointed.  */
   sp = gdbarch_push_dummy_call (gdbarch, function, get_current_regcache (),
-				bp_addr, nargs, args, sp, return_method,
-				struct_addr);
+				bp_addr, args.size (), args.data (),
+				sp, return_method, struct_addr);
 
   /* Set up a frame ID for the dummy frame so we can pass it to
      set_momentary_breakpoint.  We need to give the breakpoint a frame
diff --git a/gdb/infcall.h b/gdb/infcall.h
index 8b2195019c..c6b451ca6e 100644
--- a/gdb/infcall.h
+++ b/gdb/infcall.h
@@ -21,6 +21,7 @@
 #define INFCALL_H
 
 #include "dummy-frame.h"
+#include "common/array-view.h"
 
 struct value;
 struct type;
@@ -37,10 +38,10 @@ extern CORE_ADDR find_function_addr (struct value *function,
 
 /* Perform a function call in the inferior.
 
-   ARGS is a vector of values of arguments (NARGS of them).  FUNCTION
-   is a value, the function to be called.  Returns a value
-   representing what the function returned.  May fail to return, if a
-   breakpoint or signal is hit during the execution of the function.
+   ARGS is a vector of values of arguments.  FUNCTION is a value, the
+   function to be called.  Returns a value representing what the
+   function returned.  May fail to return, if a breakpoint or signal
+   is hit during the execution of the function.
 
    DFEAULT_RETURN_TYPE is used as function return type if the return
    type is unknown.  This is used when calling functions with no debug
@@ -50,8 +51,7 @@ extern CORE_ADDR find_function_addr (struct value *function,
 
 extern struct value *call_function_by_hand (struct value *function,
 					    type *default_return_type,
-					    int nargs,
-					    struct value **args);
+					    gdb::array_view<value *> args);
 
 /* Similar to call_function_by_hand and additional call
    register_dummy_frame_dtor with DUMMY_DTOR and DUMMY_DTOR_DATA for the
@@ -60,8 +60,7 @@ extern struct value *call_function_by_hand (struct value *function,
 extern struct value *
   call_function_by_hand_dummy (struct value *function,
 			       type *default_return_type,
-			       int nargs,
-			       struct value **args,
+			       gdb::array_view<value *> args,
 			       dummy_frame_dtor_ftype *dummy_dtor,
 			       void *dummy_dtor_data);
 
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 74d5c195d2..0f87d97c6e 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -456,7 +456,7 @@ inferior_call_waitpid (ptid_t pptid, int pid)
 {
   struct objfile *waitpid_objf;
   struct value *waitpid_fn = NULL;
-  struct value *argv[4], *retv;
+  struct value *argv[3], *retv;
   struct gdbarch *gdbarch = get_current_arch ();
   struct fork_info *oldfp = NULL, *newfp = NULL;
   struct cleanup *old_cleanup;
@@ -490,9 +490,8 @@ inferior_call_waitpid (ptid_t pptid, int pid)
   argv[0] = value_from_longest (builtin_type (gdbarch)->builtin_int, pid);
   argv[1] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr, 0);
   argv[2] = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
-  argv[3] = 0;
 
-  retv = call_function_by_hand (waitpid_fn, NULL, 3, argv);
+  retv = call_function_by_hand (waitpid_fn, NULL, argv);
   if (value_as_long (retv) < 0)
     goto out;
 
@@ -704,7 +703,7 @@ checkpoint_command (const char *args, int from_tty)
     scoped_restore save_pid
       = make_scoped_restore (&checkpointing_pid, inferior_ptid.pid ());
 
-    ret = call_function_by_hand (fork_fn, NULL, 0, &ret);
+    ret = call_function_by_hand (fork_fn, NULL, {});
   }
 
   if (!ret)	/* Probably can't happen.  */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 2c766808f0..ecdb928189 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -2400,7 +2400,7 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
   arg[ARG_FD] = value_from_longest (builtin_type (gdbarch)->builtin_int, -1);
   arg[ARG_OFFSET] = value_from_longest (builtin_type (gdbarch)->builtin_int64,
 					0);
-  addr_val = call_function_by_hand (mmap_val, NULL, ARG_LAST, arg);
+  addr_val = call_function_by_hand (mmap_val, NULL, arg);
   retval = value_as_address (addr_val);
   if (retval == (CORE_ADDR) -1)
     error (_("Failed inferior mmap call for %s bytes, errno is changed."),
@@ -2429,7 +2429,7 @@ linux_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
   /* Assuming sizeof (unsigned long) == sizeof (size_t).  */
   arg[ARG_LENGTH] = value_from_ulongest
 		    (builtin_type (gdbarch)->builtin_unsigned_long, size);
-  retval_val = call_function_by_hand (munmap_val, NULL, ARG_LAST, arg);
+  retval_val = call_function_by_hand (munmap_val, NULL, arg);
   retval = value_as_long (retval_val);
   if (retval != 0)
     warning (_("Failed inferior munmap call at %s for %s bytes, "
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 6da8af1a46..d51362a4d3 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -132,7 +132,7 @@ lookup_objc_class (struct gdbarch *gdbarch, const char *classname)
   classval = value_coerce_array (classval);
   return (CORE_ADDR) value_as_long (call_function_by_hand (function,
 							   NULL,
-							   1, &classval));
+							   classval));
 }
 
 CORE_ADDR
@@ -160,7 +160,7 @@ lookup_child_selector (struct gdbarch *gdbarch, const char *selname)
   selstring = value_coerce_array (value_string (selname, 
 						strlen (selname) + 1,
 						char_type));
-  return value_as_long (call_function_by_hand (function, NULL, 1, &selstring));
+  return value_as_long (call_function_by_hand (function, NULL, selstring));
 }
 
 struct value * 
@@ -181,13 +181,12 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
   if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0).minsym)
     {
       function = find_function_in_inferior("_NSNewStringFromCString", NULL);
-      nsstringValue = call_function_by_hand(function,
-					    NULL, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function, NULL, stringValue[2]);
     }
   else if (lookup_minimal_symbol("istr", 0, 0).minsym)
     {
       function = find_function_in_inferior("istr", NULL);
-      nsstringValue = call_function_by_hand(function, NULL, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function, NULL, stringValue[2]);
     }
   else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0).minsym)
     {
@@ -199,7 +198,7 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
 	(type, lookup_objc_class (gdbarch, "NSString"));
       stringValue[1] = value_from_longest 
 	(type, lookup_child_selector (gdbarch, "stringWithCString:"));
-      nsstringValue = call_function_by_hand(function, NULL, 3, &stringValue[0]);
+      nsstringValue = call_function_by_hand(function, NULL, stringValue);
     }
   else
     error (_("NSString: internal error -- no way to create new NSString"));
@@ -1189,7 +1188,7 @@ print_object_command (const char *args, int from_tty)
   if (function == NULL)
     error (_("Unable to locate _NSPrintForDebugger in child process"));
 
-  description = call_function_by_hand (function, NULL, 1, &object);
+  description = call_function_by_hand (function, NULL, object);
 
   string_addr = value_as_long (description);
   if (string_addr == 0)
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index fe2adcc19c..d21c2faf64 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -917,10 +917,10 @@ valpy_call (PyObject *self, PyObject *args, PyObject *keywords)
   TRY
     {
       scoped_value_mark free_values;
-      struct value *return_value;
 
-      return_value = call_function_by_hand (function, NULL,
-					    args_count, vargs);
+      value *return_value
+	= call_function_by_hand (function, NULL,
+				 gdb::make_array_view (vargs, args_count));
       result = value_to_value_object (return_value);
     }
   CATCH (except, RETURN_MASK_ALL)
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 0a327ee619..5099185a0f 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1172,7 +1172,7 @@ rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     result = value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
   else
-    result = call_function_by_hand (function, NULL, num_args + 1, args.data ());
+    result = call_function_by_hand (function, NULL, args);
   return result;
 }
 
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 1020167757..78a93e34b0 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -2041,7 +2041,7 @@ flush_ea_cache (void)
       type = lookup_pointer_type (type);
       addr = BMSYMBOL_VALUE_ADDRESS (msymbol);
 
-      call_function_by_hand (value_from_pointer (type, addr), NULL, 0, NULL);
+      call_function_by_hand (value_from_pointer (type, addr), NULL, {});
     }
 }
 
diff --git a/gdb/unittests/array-view-selftests.c b/gdb/unittests/array-view-selftests.c
index 3116ab2721..74defa1b40 100644
--- a/gdb/unittests/array-view-selftests.c
+++ b/gdb/unittests/array-view-selftests.c
@@ -483,6 +483,19 @@ run_tests ()
     gdb::array_view<Vec> view_elem = elem;
     SELF_CHECK (view_elem.size () == 1);
   }
+
+  /* gdb::make_array_view, int length.  */
+  {
+    gdb_byte data[] = {0x55, 0x66, 0x77, 0x88};
+    int len = sizeof (data) / sizeof (data[0]);
+    auto view = gdb::make_array_view (data, len);
+
+    SELF_CHECK (view.data () == data);
+    SELF_CHECK (view.size () == len);
+
+    for (size_t i = 0; i < len; i++)
+      SELF_CHECK (view[i] == data[i]);
+  }
 }
 
 } /* namespace array_view_tests */
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 807cdd5dbd..875f5477c2 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -502,8 +502,8 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	    = TYPE_TARGET_TYPE (check_typedef (value_type (argvec[0])));
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
-      return call_function_by_hand (argvec[0], NULL, 2 - static_memfuncp,
-				    argvec + 1);
+      return call_function_by_hand (argvec[0], NULL,
+				    {argvec + 1, 2u - static_memfuncp});
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
@@ -618,7 +618,8 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	    = TYPE_TARGET_TYPE (check_typedef (value_type (argvec[0])));
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
-      return call_function_by_hand (argvec[0], NULL, nargs, argvec + 1);
+      return call_function_by_hand (argvec[0], NULL,
+				    gdb::make_array_view (argvec + 1, nargs));
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
diff --git a/gdb/valops.c b/gdb/valops.c
index c45caefbf1..4758b5cdfc 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -184,7 +184,7 @@ value_allocate_space_in_inferior (int len)
   struct value *blocklen;
 
   blocklen = value_from_longest (builtin_type (gdbarch)->builtin_int, len);
-  val = call_function_by_hand (val, NULL, 1, &blocklen);
+  val = call_function_by_hand (val, NULL, blocklen);
   if (value_logical_not (val))
     {
       if (!target_has_execution)
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/6] Eliminate make_symbol_overload_list-related globals & cleanup
  2018-10-17 17:25   ` Simon Marchi
@ 2018-11-21 12:47     ` Pedro Alves
  0 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2018-11-21 12:47 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 10/17/2018 06:25 PM, Simon Marchi wrote:
> On 2018-10-15 11:11 a.m., Pedro Alves wrote:
>> This gets rid of a few globals and a cleanup.
>>
>> make_symbol_overload_list & friends currently maintain a global
>> open-coded vector.  Reimplement that with a std::vector, trickled down
>> through the functions.  Rename a few functions from "make_" to "add_"
>> for clarity.
> 
> LGTM, my only comment would be to avoid non-const passing by reference, as in
> the previous patch.
Done.  Here's what I merged.

From 0891c3cc132495ad7b323896efae4f91eca87c6c Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 21 Nov 2018 11:55:13 +0000
Subject: [PATCH 3/6] Eliminate make_symbol_overload_list-related globals &
 cleanup

This gets rid of a few globals and a cleanup.

make_symbol_overload_list & friends currently maintain a global
open-coded vector.  Reimplement that with a std::vector, trickled down
through the functions.  Rename a few functions from "make_" to "add_"
for clarity.

gdb/ChangeLog:
2018-11-21  Pedro Alves  <palves@redhat.com>

	* cp-support.c (sym_return_val_size, sym_return_val_index)
	(sym_return_val): Delete.
	(overload_list_add_symbol): Add std::vector parameter.  Adjust to
	add to the vector.
	(make_symbol_overload_list): Adjust to return a std::vector
	instead of maintaining a global open coded vector.
	(make_symbol_overload_list_block): Add std::vector parameter.
	(make_symbol_overload_list_block): Rename to ...
	(add_symbol_overload_list_block): ... this and add std::vector
	parameter.
	(make_symbol_overload_list_namespace): Rename to ...
	(add_symbol_overload_list_namespace): ... this and add std::vector
	parameter.
	(make_symbol_overload_list_adl_namespace): Rename to ...
	(add_symbol_overload_list_adl_namespace): ... this and add
	std::vector parameter.
	(make_symbol_overload_list_adl): Delete.
	(add_symbol_overload_list_adl): New.
	(make_symbol_overload_list_using): Rename to ...
	(add_symbol_overload_list_using): ... this and add std::vector
	parameter.
	(make_symbol_overload_list_qualified): Rename to ...
	(add_symbol_overload_list_qualified): ... this and add std::vector
	parameter.
	* cp-support.h: Include "common/array-view.h" and <vector>.
	(make_symbol_overload_list): Change return type to std::vector.
	(make_symbol_overload_list_adl): Delete declaration.
	(add_symbol_overload_list_adl): New declaration.
	* valops.c (find_overload_match): Local 'oload_syms' now a
	std::vector.
	(find_oload_champ_namespace): 'oload_syms' parameter now a
	std::vector pointer.
	(find_oload_champ_namespace_loop): 'oload_syms' parameter now a
	std::vector pointer.  Adjust to new make_symbol_overload_list
	interface.
---
 gdb/ChangeLog    |  38 +++++++++++++++
 gdb/cp-support.c | 142 ++++++++++++++++++++++++-------------------------------
 gdb/cp-support.h |  13 +++--
 gdb/valops.c     |  37 ++++++---------
 4 files changed, 124 insertions(+), 106 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 27da6431b3..e808dd5dab 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,41 @@
+2018-11-21  Pedro Alves  <palves@redhat.com>
+
+	* cp-support.c (sym_return_val_size, sym_return_val_index)
+	(sym_return_val): Delete.
+	(overload_list_add_symbol): Add std::vector parameter.  Adjust to
+	add to the vector.
+	(make_symbol_overload_list): Adjust to return a std::vector
+	instead of maintaining a global open coded vector.
+	(make_symbol_overload_list_block): Add std::vector parameter.
+	(make_symbol_overload_list_block): Rename to ...
+	(add_symbol_overload_list_block): ... this and add std::vector
+	parameter.
+	(make_symbol_overload_list_namespace): Rename to ...
+	(add_symbol_overload_list_namespace): ... this and add std::vector
+	parameter.
+	(make_symbol_overload_list_adl_namespace): Rename to ...
+	(add_symbol_overload_list_adl_namespace): ... this and add
+	std::vector parameter.
+	(make_symbol_overload_list_adl): Delete.
+	(add_symbol_overload_list_adl): New.
+	(make_symbol_overload_list_using): Rename to ...
+	(add_symbol_overload_list_using): ... this and add std::vector
+	parameter.
+	(make_symbol_overload_list_qualified): Rename to ...
+	(add_symbol_overload_list_qualified): ... this and add std::vector
+	parameter.
+	* cp-support.h: Include "common/array-view.h" and <vector>.
+	(make_symbol_overload_list): Change return type to std::vector.
+	(make_symbol_overload_list_adl): Delete declaration.
+	(add_symbol_overload_list_adl): New declaration.
+	* valops.c (find_overload_match): Local 'oload_syms' now a
+	std::vector.
+	(find_oload_champ_namespace): 'oload_syms' parameter now a
+	std::vector pointer.
+	(find_oload_champ_namespace_loop): 'oload_syms' parameter now a
+	std::vector pointer.  Adjust to new make_symbol_overload_list
+	interface.
+
 2018-11-21  Pedro Alves  <palves@redhat.com>
 
 	* common/array-view.h (array_view::splice(size_type, size_t)): New.
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 25c887035c..1f95253cb0 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -48,19 +48,19 @@ static unsigned int cp_find_first_component_aux (const char *name,
 
 static void demangled_name_complaint (const char *name);
 
-/* Functions/variables related to overload resolution.  */
-
-static int sym_return_val_size = -1;
-static int sym_return_val_index;
-static struct symbol **sym_return_val;
+/* Functions related to overload resolution.  */
 
 static void overload_list_add_symbol (struct symbol *sym,
-				      const char *oload_name);
+				      const char *oload_name,
+				      std::vector<symbol *> *overload_list);
 
-static void make_symbol_overload_list_using (const char *func_name,
-					     const char *the_namespace);
+static void add_symbol_overload_list_using
+  (const char *func_name, const char *the_namespace,
+   std::vector<symbol *> *overload_list);
 
-static void make_symbol_overload_list_qualified (const char *func_name);
+static void add_symbol_overload_list_qualified
+  (const char *func_name,
+   std::vector<symbol *> *overload_list);
 
 /* The list of "maint cplus" commands.  */
 
@@ -1137,30 +1137,28 @@ cp_entire_prefix_len (const char *name)
 /* Overload resolution functions.  */
 
 /* Test to see if SYM is a symbol that we haven't seen corresponding
-   to a function named OLOAD_NAME.  If so, add it to the current
-   completion list.  */
+   to a function named OLOAD_NAME.  If so, add it to
+   OVERLOAD_LIST.  */
 
 static void
 overload_list_add_symbol (struct symbol *sym,
-			  const char *oload_name)
+			  const char *oload_name,
+			  std::vector<symbol *> *overload_list)
 {
-  int newsize;
-  int i;
-  gdb::unique_xmalloc_ptr<char> sym_name;
-
   /* If there is no type information, we can't do anything, so
      skip.  */
   if (SYMBOL_TYPE (sym) == NULL)
     return;
 
   /* skip any symbols that we've already considered.  */
-  for (i = 0; i < sym_return_val_index; ++i)
+  for (symbol *listed_sym : *overload_list)
     if (strcmp (SYMBOL_LINKAGE_NAME (sym),
-		SYMBOL_LINKAGE_NAME (sym_return_val[i])) == 0)
+		SYMBOL_LINKAGE_NAME (listed_sym)) == 0)
       return;
 
   /* Get the demangled name without parameters */
-  sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym));
+  gdb::unique_xmalloc_ptr<char> sym_name
+    = cp_remove_params (SYMBOL_NATURAL_NAME (sym));
   if (!sym_name)
     return;
 
@@ -1168,36 +1166,22 @@ overload_list_add_symbol (struct symbol *sym,
   if (strcmp (sym_name.get (), oload_name) != 0)
     return;
 
-  /* We have a match for an overload instance, so add SYM to the
-     current list of overload instances */
-  if (sym_return_val_index + 3 > sym_return_val_size)
-    {
-      newsize = (sym_return_val_size *= 2) * sizeof (struct symbol *);
-      sym_return_val = (struct symbol **)
-	xrealloc ((char *) sym_return_val, newsize);
-    }
-  sym_return_val[sym_return_val_index++] = sym;
-  sym_return_val[sym_return_val_index] = NULL;
+  overload_list->push_back (sym);
 }
 
 /* Return a null-terminated list of pointers to function symbols that
    are named FUNC_NAME and are visible within NAMESPACE.  */
 
-struct symbol **
+struct std::vector<symbol *>
 make_symbol_overload_list (const char *func_name,
 			   const char *the_namespace)
 {
-  struct cleanup *old_cleanups;
   const char *name;
+  std::vector<symbol *> overload_list;
 
-  sym_return_val_size = 100;
-  sym_return_val_index = 0;
-  sym_return_val = XNEWVEC (struct symbol *, sym_return_val_size + 1);
-  sym_return_val[0] = NULL;
-
-  old_cleanups = make_cleanup (xfree, sym_return_val);
+  overload_list.reserve (100);
 
-  make_symbol_overload_list_using (func_name, the_namespace);
+  add_symbol_overload_list_using (func_name, the_namespace, &overload_list);
 
   if (the_namespace[0] == '\0')
     name = func_name;
@@ -1211,19 +1195,17 @@ make_symbol_overload_list (const char *func_name,
       name = concatenated_name;
     }
 
-  make_symbol_overload_list_qualified (name);
-
-  discard_cleanups (old_cleanups);
-
-  return sym_return_val;
+  add_symbol_overload_list_qualified (name, &overload_list);
+  return overload_list;
 }
 
 /* Add all symbols with a name matching NAME in BLOCK to the overload
    list.  */
 
 static void
-make_symbol_overload_list_block (const char *name,
-                                 const struct block *block)
+add_symbol_overload_list_block (const char *name,
+				const struct block *block,
+				std::vector<symbol *> *overload_list)
 {
   struct block_iterator iter;
   struct symbol *sym;
@@ -1231,14 +1213,15 @@ make_symbol_overload_list_block (const char *name,
   lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
 
   ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
-    overload_list_add_symbol (sym, name);
+    overload_list_add_symbol (sym, name, overload_list);
 }
 
 /* Adds the function FUNC_NAME from NAMESPACE to the overload set.  */
 
 static void
-make_symbol_overload_list_namespace (const char *func_name,
-                                     const char *the_namespace)
+add_symbol_overload_list_namespace (const char *func_name,
+				    const char *the_namespace,
+				    std::vector<symbol *> *overload_list)
 {
   const char *name;
   const struct block *block = NULL;
@@ -1259,12 +1242,12 @@ make_symbol_overload_list_namespace (const char *func_name,
   /* Look in the static block.  */
   block = block_static_block (get_selected_block (0));
   if (block)
-    make_symbol_overload_list_block (name, block);
+    add_symbol_overload_list_block (name, block, overload_list);
 
   /* Look in the global block.  */
   block = block_global_block (block);
   if (block)
-    make_symbol_overload_list_block (name, block);
+    add_symbol_overload_list_block (name, block, overload_list);
 
 }
 
@@ -1272,8 +1255,9 @@ make_symbol_overload_list_namespace (const char *func_name,
    base types.  */
 
 static void
-make_symbol_overload_list_adl_namespace (struct type *type,
-                                         const char *func_name)
+add_symbol_overload_list_adl_namespace (struct type *type,
+					const char *func_name,
+					std::vector<symbol *> *overload_list)
 {
   char *the_namespace;
   const char *type_name;
@@ -1303,7 +1287,8 @@ make_symbol_overload_list_adl_namespace (struct type *type,
       strncpy (the_namespace, type_name, prefix_len);
       the_namespace[prefix_len] = '\0';
 
-      make_symbol_overload_list_namespace (func_name, the_namespace);
+      add_symbol_overload_list_namespace (func_name, the_namespace,
+					  overload_list);
     }
 
   /* Check public base type */
@@ -1311,28 +1296,23 @@ make_symbol_overload_list_adl_namespace (struct type *type,
     for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
       {
 	if (BASETYPE_VIA_PUBLIC (type, i))
-	  make_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type,
-								   i),
-						   func_name);
+	  add_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type, i),
+						  func_name,
+						  overload_list);
       }
 }
 
-/* Adds the overload list overload candidates for FUNC_NAME found
-   through argument dependent lookup.  */
+/* Adds to OVERLOAD_LIST the overload list overload candidates for
+   FUNC_NAME found through argument dependent lookup.  */
 
-struct symbol **
-make_symbol_overload_list_adl (struct type **arg_types, int nargs,
-                               const char *func_name)
+void
+add_symbol_overload_list_adl (gdb::array_view<type *> arg_types,
+			      const char *func_name,
+			      std::vector<symbol *> *overload_list)
 {
-  int i;
-
-  gdb_assert (sym_return_val_size != -1);
-
-  for (i = 1; i <= nargs; i++)
-    make_symbol_overload_list_adl_namespace (arg_types[i - 1],
-					     func_name);
-
-  return sym_return_val;
+  for (type *arg_type : arg_types)
+    add_symbol_overload_list_adl_namespace (arg_type, func_name,
+					    overload_list);
 }
 
 /* This applies the using directives to add namespaces to search in,
@@ -1341,8 +1321,9 @@ make_symbol_overload_list_adl (struct type **arg_types, int nargs,
    make_symbol_overload_list.  */
 
 static void
-make_symbol_overload_list_using (const char *func_name,
-				 const char *the_namespace)
+add_symbol_overload_list_using (const char *func_name,
+				const char *the_namespace,
+				std::vector<symbol *> *overload_list)
 {
   struct using_direct *current;
   const struct block *block;
@@ -1374,13 +1355,15 @@ make_symbol_overload_list_using (const char *func_name,
 	    scoped_restore reset_directive_searched
 	      = make_scoped_restore (&current->searched, 1);
 
-	    make_symbol_overload_list_using (func_name,
-					     current->import_src);
+	    add_symbol_overload_list_using (func_name,
+					    current->import_src,
+					    overload_list);
 	  }
       }
 
   /* Now, add names for this namespace.  */
-  make_symbol_overload_list_namespace (func_name, the_namespace);
+  add_symbol_overload_list_namespace (func_name, the_namespace,
+				      overload_list);
 }
 
 /* This does the bulk of the work of finding overloaded symbols.
@@ -1388,7 +1371,8 @@ make_symbol_overload_list_using (const char *func_name,
    (possibly including namespace info).  */
 
 static void
-make_symbol_overload_list_qualified (const char *func_name)
+add_symbol_overload_list_qualified (const char *func_name,
+				    std::vector<symbol *> *overload_list)
 {
   struct compunit_symtab *cust;
   struct objfile *objfile;
@@ -1407,7 +1391,7 @@ make_symbol_overload_list_qualified (const char *func_name)
      complete on local vars.  */
 
   for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
-    make_symbol_overload_list_block (func_name, b);
+    add_symbol_overload_list_block (func_name, b, overload_list);
 
   surrounding_static_block = block_static_block (get_selected_block (0));
 
@@ -1418,7 +1402,7 @@ make_symbol_overload_list_qualified (const char *func_name)
   {
     QUIT;
     b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
-    make_symbol_overload_list_block (func_name, b);
+    add_symbol_overload_list_block (func_name, b, overload_list);
   }
 
   ALL_COMPUNITS (objfile, cust)
@@ -1428,7 +1412,7 @@ make_symbol_overload_list_qualified (const char *func_name)
     /* Don't do this block twice.  */
     if (b == surrounding_static_block)
       continue;
-    make_symbol_overload_list_block (func_name, b);
+    add_symbol_overload_list_block (func_name, b, overload_list);
   }
 }
 
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 4e26921595..0402df02d3 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -28,6 +28,8 @@
 #include "vec.h"
 #include "gdb_vecs.h"
 #include "gdb_obstack.h"
+#include "common/array-view.h"
+#include <vector>
 
 /* Opaque declarations.  */
 
@@ -107,12 +109,13 @@ extern gdb::unique_xmalloc_ptr<char> cp_remove_params
 extern gdb::unique_xmalloc_ptr<char> cp_remove_params_if_any
   (const char *demangled_name, bool completion_mode);
 
-extern struct symbol **make_symbol_overload_list (const char *,
-						  const char *);
+extern std::vector<symbol *> make_symbol_overload_list (const char *,
+							const char *);
 
-extern struct symbol **make_symbol_overload_list_adl (struct type **arg_types,
-                                                      int nargs,
-                                                      const char *func_name);
+extern void add_symbol_overload_list_adl
+  (gdb::array_view<type *> arg_types,
+   const char *func_name,
+   std::vector<symbol *> *overload_list);
 
 extern struct type *cp_lookup_rtti_type (const char *name,
 					 struct block *block);
diff --git a/gdb/valops.c b/gdb/valops.c
index f0e53a7ce9..7fbedd77bb 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -56,13 +56,13 @@ static struct value *search_struct_method (const char *, struct value **,
 
 static int find_oload_champ_namespace (gdb::array_view<value *> args,
 				       const char *, const char *,
-				       struct symbol ***,
+				       std::vector<symbol *> *oload_syms,
 				       struct badness_vector **,
 				       const int no_adl);
 
 static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 					    const char *, const char *,
-					    int, struct symbol ***,
+					    int, std::vector<symbol *> *oload_syms,
 					    struct badness_vector **, int *,
 					    const int no_adl);
 
@@ -2517,7 +2517,7 @@ find_overload_match (gdb::array_view<value *> args,
   /* For methods, the list of overloaded methods.  */
   struct fn_field *fns_ptr = NULL;
   /* For non-methods, the list of overloaded function symbols.  */
-  struct symbol **oload_syms = NULL;
+  std::vector<symbol *> oload_syms;
   /* For xmethods, the vector of xmethod workers.  */
   std::vector<xmethod_worker_up> xm_worker_vec;
   /* Number of overloaded instances being considered.  */
@@ -2717,7 +2717,6 @@ find_overload_match (gdb::array_view<value *> args,
 	func_match_quality = classify_oload_match (func_badness,
 						   args.size (), 0);
 
-      make_cleanup (xfree, oload_syms);
       make_cleanup (xfree, func_badness);
     }
 
@@ -2857,7 +2856,7 @@ static int
 find_oload_champ_namespace (gdb::array_view<value *> args,
 			    const char *func_name,
 			    const char *qualified_name,
-			    struct symbol ***oload_syms,
+			    std::vector<symbol *> *oload_syms,
 			    struct badness_vector **oload_champ_bv,
 			    const int no_adl)
 {
@@ -2887,17 +2886,15 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				 const char *func_name,
 				 const char *qualified_name,
 				 int namespace_len,
-				 struct symbol ***oload_syms,
+				 std::vector<symbol *> *oload_syms,
 				 struct badness_vector **oload_champ_bv,
 				 int *oload_champ,
 				 const int no_adl)
 {
   int next_namespace_len = namespace_len;
   int searched_deeper = 0;
-  int num_fns = 0;
   struct cleanup *old_cleanups;
   int new_oload_champ;
-  struct symbol **new_oload_syms;
   struct badness_vector *new_oload_champ_bv;
   char *new_namespace;
 
@@ -2910,7 +2907,6 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     cp_find_first_component (qualified_name + next_namespace_len);
 
   /* Initialize these to values that can safely be xfree'd.  */
-  *oload_syms = NULL;
   *oload_champ_bv = NULL;
 
   /* First, see if we have a deeper namespace we can search in.
@@ -2938,13 +2934,13 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
      because this overload mechanism only gets called if there's a
      function symbol to start off with.)  */
 
-  old_cleanups = make_cleanup (xfree, *oload_syms);
-  make_cleanup (xfree, *oload_champ_bv);
+  old_cleanups = make_cleanup (xfree, *oload_champ_bv);
   new_namespace = (char *) alloca (namespace_len + 1);
   strncpy (new_namespace, qualified_name, namespace_len);
   new_namespace[namespace_len] = '\0';
-  new_oload_syms = make_symbol_overload_list (func_name,
-					      new_namespace);
+
+  std::vector<symbol *> new_oload_syms
+    = make_symbol_overload_list (func_name, new_namespace);
 
   /* If we have reached the deepest level perform argument
      determined lookup.  */
@@ -2958,14 +2954,12 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 	alloca (args.size () * (sizeof (struct type *)));
       for (ix = 0; ix < args.size (); ix++)
 	arg_types[ix] = value_type (args[ix]);
-      make_symbol_overload_list_adl (arg_types, args.size (), func_name);
+      add_symbol_overload_list_adl ({arg_types, args.size ()}, func_name,
+				    &new_oload_syms);
     }
 
-  while (new_oload_syms[num_fns])
-    ++num_fns;
-
-  new_oload_champ = find_oload_champ (args, num_fns,
-				      NULL, NULL, new_oload_syms,
+  new_oload_champ = find_oload_champ (args, new_oload_syms.size (),
+				      NULL, NULL, new_oload_syms.data (),
 				      &new_oload_champ_bv);
 
   /* Case 1: We found a good match.  Free earlier matches (if any),
@@ -2978,7 +2972,7 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
   if (new_oload_champ != -1
       && classify_oload_match (new_oload_champ_bv, args.size (), 0) == STANDARD)
     {
-      *oload_syms = new_oload_syms;
+      *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
       *oload_champ_bv = new_oload_champ_bv;
       do_cleanups (old_cleanups);
@@ -2986,14 +2980,13 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     }
   else if (searched_deeper)
     {
-      xfree (new_oload_syms);
       xfree (new_oload_champ_bv);
       discard_cleanups (old_cleanups);
       return 0;
     }
   else
     {
-      *oload_syms = new_oload_syms;
+      *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
       *oload_champ_bv = new_oload_champ_bv;
       do_cleanups (old_cleanups);
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/6] C++ify badness_vector, fix leaks
  2018-10-17 17:44   ` Simon Marchi
@ 2018-11-21 12:47     ` Pedro Alves
  0 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2018-11-21 12:47 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 10/17/2018 06:44 PM, Simon Marchi wrote:
> LGTM, just a tiny comment:
> 
> On 2018-10-15 11:11 a.m., Pedro Alves wrote:
>> @@ -2848,7 +2842,7 @@ find_overload_match (gdb::array_view<value *> args,
>>     contained in QUALIFIED_NAME until it either finds a good match or
>>     runs out of namespaces.  It stores the overloaded functions in
>>     *OLOAD_SYMS, and the badness vector in *OLOAD_CHAMP_BV.  The
>> -   calling function is responsible for freeing *OLOAD_SYMS and
>> +   calling function is responsible for clearing *OLOAD_SYMS and
>>     *OLOAD_CHAMP_BV.  If NO_ADL, argument dependent lookup is not 
>>     performned.  */
> 
> The previous comment meant that the caller was responsible to free the data
> after this function is called.  From what I understand, the new comment means
> the caller is responsible to pass empty vectors as inputs, is that right?  If
> so, it would be clearer to say "the calling function is responsible for passing
> empty vectors for *OLOAD_SYMS and *OLOAD_CHAMP_BV".

Yeah.  I just removed that sentence, since it wasn't really adding anything
anymore.

> 
> I know the opposite wouldn't really make sense (asking the caller to clear the
> vector after the call), but like this it sounds ambiguous.
Here's what I pushed.

From fa7819ae688b390009353bdf7dec15ece3ade159 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 21 Nov 2018 11:55:14 +0000
Subject: [PATCH 4/6] C++ify badness_vector, fix leaks

badness_vector is currently an open coded vector.  This reimplements
it as a std::vector.

This fixes a few leaks as well:

 - find_oload_champ is leaking every badness vector calculated bar the
   one returned.

 - bv->rank is always leaked, since callers of rank_function only
   xfree the badness_vector pointer, not bv->rank.

gdb/ChangeLog:
2018-11-21  Pedro Alves  <palves@redhat.com>

	* gdbtypes.c (compare_badness): Change type of parameters to const
	reference.  Adjust to badness_vector being a std::vector now.
	(rank_function): Adjust to badness_vector being a std::vector now.
	* gdbtypes.h (badness_vector): Now a typedef to std::vector.
	(LENGTH_MATCH): Delete.
	(compare_badness): Change type of parameters to const reference.
	(rank_function): Return a badness_vector by value now.
	(find_overload_match): Adjust to badness_vector being a
	std::vector now.  Remove cleanups.
	(find_oload_champ_namespace): 'oload_champ_bv' parameter now a
	badness_vector pointer.
	(find_oload_champ_namespace_loop): 'oload_champ_bv' parameter now
	a badness_vector pointer.  Adjust to badness_vector being a
	std::vector now.  Remove cleanups.
	(find_oload_champ): 'oload_champ_bv' parameter now
	a badness_vector pointer.  Adjust to badness_vector being a
	std::vector now.  Remove cleanups.
---
 gdb/ChangeLog  | 20 +++++++++++++++
 gdb/gdbtypes.c | 43 ++++++++++++++++----------------
 gdb/gdbtypes.h | 17 +++++--------
 gdb/valops.c   | 78 ++++++++++++++++++++--------------------------------------
 4 files changed, 74 insertions(+), 84 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e808dd5dab..5ae9ae7b1b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,23 @@
+2018-11-21  Pedro Alves  <palves@redhat.com>
+
+	* gdbtypes.c (compare_badness): Change type of parameters to const
+	reference.  Adjust to badness_vector being a std::vector now.
+	(rank_function): Adjust to badness_vector being a std::vector now.
+	* gdbtypes.h (badness_vector): Now a typedef to std::vector.
+	(LENGTH_MATCH): Delete.
+	(compare_badness): Change type of parameters to const reference.
+	(rank_function): Return a badness_vector by value now.
+	(find_overload_match): Adjust to badness_vector being a
+	std::vector now.  Remove cleanups.
+	(find_oload_champ_namespace): 'oload_champ_bv' parameter now a
+	badness_vector pointer.
+	(find_oload_champ_namespace_loop): 'oload_champ_bv' parameter now
+	a badness_vector pointer.  Adjust to badness_vector being a
+	std::vector now.  Remove cleanups.
+	(find_oload_champ): 'oload_champ_bv' parameter now
+	a badness_vector pointer.  Adjust to badness_vector being a
+	std::vector now.  Remove cleanups.
+
 2018-11-21  Pedro Alves  <palves@redhat.com>
 
 	* cp-support.c (sym_return_val_size, sym_return_val_index)
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 4160d996de..39b7a99017 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3426,21 +3426,21 @@ compare_ranks (struct rank a, struct rank b)
    3 => A is worse than B  */
 
 int
-compare_badness (struct badness_vector *a, struct badness_vector *b)
+compare_badness (const badness_vector &a, const badness_vector &b)
 {
   int i;
   int tmp;
   short found_pos = 0;		/* any positives in c? */
   short found_neg = 0;		/* any negatives in c? */
 
-  /* differing lengths => incomparable */
-  if (a->length != b->length)
+  /* differing sizes => incomparable */
+  if (a.size () != b.size ())
     return 1;
 
   /* Subtract b from a */
-  for (i = 0; i < a->length; i++)
+  for (i = 0; i < a.size (); i++)
     {
-      tmp = compare_ranks (b->rank[i], a->rank[i]);
+      tmp = compare_ranks (b[i], a[i]);
       if (tmp > 0)
 	found_pos = 1;
       else if (tmp < 0)
@@ -3465,19 +3465,16 @@ compare_badness (struct badness_vector *a, struct badness_vector *b)
 }
 
 /* Rank a function by comparing its parameter types (PARMS), to the
-   types of an argument list (ARGS).  Return a pointer to a badness
-   vector.  This has ARGS.size() + 1 entries.  */
+   types of an argument list (ARGS).  Return the badness vector.  This
+   has ARGS.size() + 1 entries.  */
 
-struct badness_vector *
+badness_vector
 rank_function (gdb::array_view<type *> parms,
 	       gdb::array_view<value *> args)
 {
-  int i;
-  struct badness_vector *bv = XNEW (struct badness_vector);
-  size_t min_len = std::min (parms.size (), args.size ());
-
-  bv->length = args.size () + 1;	/* add 1 for the length-match rank.  */
-  bv->rank = XNEWVEC (struct rank, args.size () + 1);
+  /* add 1 for the length-match rank.  */
+  badness_vector bv;
+  bv.reserve (1 + args.size ());
 
   /* First compare the lengths of the supplied lists.
      If there is a mismatch, set it to a high value.  */
@@ -3486,18 +3483,20 @@ rank_function (gdb::array_view<type *> parms,
      arguments and ellipsis parameter lists, we should consider those
      and rank the length-match more finely.  */
 
-  LENGTH_MATCH (bv) = (args.size () != parms.size ())
-		      ? LENGTH_MISMATCH_BADNESS
-		      : EXACT_MATCH_BADNESS;
+  bv.push_back ((args.size () != parms.size ())
+		? LENGTH_MISMATCH_BADNESS
+		: EXACT_MATCH_BADNESS);
 
   /* Now rank all the parameters of the candidate function.  */
-  for (i = 1; i <= min_len; i++)
-    bv->rank[i] = rank_one_type (parms[i - 1], value_type (args[i - 1]),
-				 args[i - 1]);
+  size_t min_len = std::min (parms.size (), args.size ());
+
+  for (size_t i = 0; i < min_len; i++)
+    bv.push_back (rank_one_type (parms[i], value_type (args[i]),
+				 args[i]));
 
   /* If more arguments than parameters, add dummy entries.  */
-  for (i = min_len + 1; i <= args.size (); i++)
-    bv->rank[i] = TOO_FEW_PARAMS_BADNESS;
+  for (size_t i = min_len; i < args.size (); i++)
+    bv.push_back (TOO_FEW_PARAMS_BADNESS);
 
   return bv;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 731b18d082..f0adec7a20 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1095,13 +1095,9 @@ struct rank
     short subrank;
   };
 
-/* * Struct used for ranking a function for overload resolution.  */
+/* * Used for ranking a function for overload resolution.  */
 
-struct badness_vector
-  {
-    int length;
-    struct rank *rank;
-  };
+typedef std::vector<rank> badness_vector;
 
 /* * GNAT Ada-specific information for various Ada types.  */
 
@@ -1983,8 +1979,6 @@ extern int is_unique_ancestor (struct type *, struct value *);
 
 /* Overload resolution */
 
-#define LENGTH_MATCH(bv) ((bv)->rank[0])
-
 /* * Badness if parameter list length doesn't match arg list length.  */
 extern const struct rank LENGTH_MISMATCH_BADNESS;
 
@@ -2043,10 +2037,11 @@ extern const struct rank NS_INTEGER_POINTER_CONVERSION_BADNESS;
 extern struct rank sum_ranks (struct rank a, struct rank b);
 extern int compare_ranks (struct rank a, struct rank b);
 
-extern int compare_badness (struct badness_vector *, struct badness_vector *);
+extern int compare_badness (const badness_vector &,
+			    const badness_vector &);
 
-extern struct badness_vector *rank_function (gdb::array_view<type *> parms,
-					     gdb::array_view<value *> args);
+extern badness_vector rank_function (gdb::array_view<type *> parms,
+				     gdb::array_view<value *> args);
 
 extern struct rank rank_one_type (struct type *, struct type *,
 				  struct value *);
diff --git a/gdb/valops.c b/gdb/valops.c
index 7fbedd77bb..1b4a8e123c 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -57,27 +57,26 @@ static struct value *search_struct_method (const char *, struct value **,
 static int find_oload_champ_namespace (gdb::array_view<value *> args,
 				       const char *, const char *,
 				       std::vector<symbol *> *oload_syms,
-				       struct badness_vector **,
+				       badness_vector *,
 				       const int no_adl);
 
 static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 					    const char *, const char *,
 					    int, std::vector<symbol *> *oload_syms,
-					    struct badness_vector **, int *,
+					    badness_vector *, int *,
 					    const int no_adl);
 
 static int find_oload_champ (gdb::array_view<value *> args, int,
 			     struct fn_field *,
 			     const std::vector<xmethod_worker_up> *,
-			     struct symbol **, struct badness_vector **);
+			     struct symbol **, badness_vector *);
 
 static int oload_method_static_p (struct fn_field *, int);
 
 enum oload_classification { STANDARD, NON_STANDARD, INCOMPATIBLE };
 
-static enum
-oload_classification classify_oload_match (struct badness_vector *,
-					   int, int);
+static enum oload_classification classify_oload_match
+  (const badness_vector &, int, int);
 
 static struct value *value_struct_elt_for_reference (struct type *,
 						     int, struct type *,
@@ -2508,10 +2507,10 @@ find_overload_match (gdb::array_view<value *> args,
   int ext_method_oload_champ = -1;
 
   /* The measure for the current best match.  */
-  struct badness_vector *method_badness = NULL;
-  struct badness_vector *func_badness = NULL;
-  struct badness_vector *ext_method_badness = NULL;
-  struct badness_vector *src_method_badness = NULL;
+  badness_vector method_badness;
+  badness_vector func_badness;
+  badness_vector ext_method_badness;
+  badness_vector src_method_badness;
 
   struct value *temp = obj;
   /* For methods, the list of overloaded methods.  */
@@ -2584,8 +2583,6 @@ find_overload_match (gdb::array_view<value *> args,
 	  src_method_match_quality = classify_oload_match
 	    (src_method_badness, args.size (),
 	     oload_method_static_p (fns_ptr, src_method_oload_champ));
-
-	  make_cleanup (xfree, src_method_badness);
 	}
 
       if (!xm_worker_vec.empty ())
@@ -2594,7 +2591,6 @@ find_overload_match (gdb::array_view<value *> args,
 						     NULL, &ext_method_badness);
 	  ext_method_match_quality = classify_oload_match (ext_method_badness,
 							   args.size (), 0);
-	  make_cleanup (xfree, ext_method_badness);
 	}
 
       if (src_method_oload_champ >= 0 && ext_method_oload_champ >= 0)
@@ -2716,8 +2712,6 @@ find_overload_match (gdb::array_view<value *> args,
       if (func_oload_champ >= 0)
 	func_match_quality = classify_oload_match (func_badness,
 						   args.size (), 0);
-
-      make_cleanup (xfree, func_badness);
     }
 
   /* Did we find a match ?  */
@@ -2847,17 +2841,15 @@ find_overload_match (gdb::array_view<value *> args,
 /* Find the best overload match, searching for FUNC_NAME in namespaces
    contained in QUALIFIED_NAME until it either finds a good match or
    runs out of namespaces.  It stores the overloaded functions in
-   *OLOAD_SYMS, and the badness vector in *OLOAD_CHAMP_BV.  The
-   calling function is responsible for freeing *OLOAD_SYMS and
-   *OLOAD_CHAMP_BV.  If NO_ADL, argument dependent lookup is not 
-   performned.  */
+   *OLOAD_SYMS, and the badness vector in *OLOAD_CHAMP_BV.  If NO_ADL,
+   argument dependent lookup is not performned.  */
 
 static int
 find_oload_champ_namespace (gdb::array_view<value *> args,
 			    const char *func_name,
 			    const char *qualified_name,
 			    std::vector<symbol *> *oload_syms,
-			    struct badness_vector **oload_champ_bv,
+			    badness_vector *oload_champ_bv,
 			    const int no_adl)
 {
   int oload_champ;
@@ -2876,10 +2868,7 @@ find_oload_champ_namespace (gdb::array_view<value *> args,
    how deep we've looked for namespaces, and the champ is stored in
    OLOAD_CHAMP.  The return value is 1 if the champ is a good one, 0
    if it isn't.  Other arguments are the same as in
-   find_oload_champ_namespace
-
-   It is the caller's responsibility to free *OLOAD_SYMS and
-   *OLOAD_CHAMP_BV.  */
+   find_oload_champ_namespace.  */
 
 static int
 find_oload_champ_namespace_loop (gdb::array_view<value *> args,
@@ -2887,15 +2876,13 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				 const char *qualified_name,
 				 int namespace_len,
 				 std::vector<symbol *> *oload_syms,
-				 struct badness_vector **oload_champ_bv,
+				 badness_vector *oload_champ_bv,
 				 int *oload_champ,
 				 const int no_adl)
 {
   int next_namespace_len = namespace_len;
   int searched_deeper = 0;
-  struct cleanup *old_cleanups;
   int new_oload_champ;
-  struct badness_vector *new_oload_champ_bv;
   char *new_namespace;
 
   if (next_namespace_len != 0)
@@ -2906,9 +2893,6 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
   next_namespace_len +=
     cp_find_first_component (qualified_name + next_namespace_len);
 
-  /* Initialize these to values that can safely be xfree'd.  */
-  *oload_champ_bv = NULL;
-
   /* First, see if we have a deeper namespace we can search in.
      If we get a good match there, use it.  */
 
@@ -2934,7 +2918,6 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
      because this overload mechanism only gets called if there's a
      function symbol to start off with.)  */
 
-  old_cleanups = make_cleanup (xfree, *oload_champ_bv);
   new_namespace = (char *) alloca (namespace_len + 1);
   strncpy (new_namespace, qualified_name, namespace_len);
   new_namespace[namespace_len] = '\0';
@@ -2958,6 +2941,7 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				    &new_oload_syms);
     }
 
+  badness_vector new_oload_champ_bv;
   new_oload_champ = find_oload_champ (args, new_oload_syms.size (),
 				      NULL, NULL, new_oload_syms.data (),
 				      &new_oload_champ_bv);
@@ -2974,22 +2958,18 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     {
       *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
-      *oload_champ_bv = new_oload_champ_bv;
-      do_cleanups (old_cleanups);
+      *oload_champ_bv = std::move (new_oload_champ_bv);
       return 1;
     }
   else if (searched_deeper)
     {
-      xfree (new_oload_champ_bv);
-      discard_cleanups (old_cleanups);
       return 0;
     }
   else
     {
       *oload_syms = std::move (new_oload_syms);
       *oload_champ = new_oload_champ;
-      *oload_champ_bv = new_oload_champ_bv;
-      do_cleanups (old_cleanups);
+      *oload_champ_bv = std::move (new_oload_champ_bv);
       return 0;
     }
 }
@@ -3003,20 +2983,18 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
    or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
 
    Return the index of the best match; store an indication of the
-   quality of the match in OLOAD_CHAMP_BV.
-
-   It is the caller's responsibility to free *OLOAD_CHAMP_BV.  */
+   quality of the match in OLOAD_CHAMP_BV.  */
 
 static int
 find_oload_champ (gdb::array_view<value *> args,
 		  int num_fns, struct fn_field *fns_ptr,
 		  const std::vector<xmethod_worker_up> *xm_worker_vec,
 		  struct symbol **oload_syms,
-		  struct badness_vector **oload_champ_bv)
+		  badness_vector *oload_champ_bv)
 {
   int ix;
   /* A measure of how good an overloaded instance is.  */
-  struct badness_vector *bv;
+  badness_vector bv;
   /* Index of best overloaded function.  */
   int oload_champ = -1;
   /* Current ambiguity state for overload resolution.  */
@@ -3029,8 +3007,6 @@ find_oload_champ (gdb::array_view<value *> args,
   gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) + (xm_worker_vec != NULL)
 	      == 1);
 
-  *oload_champ_bv = NULL;
-
   int fn_count = xm_worker_vec != NULL ? xm_worker_vec->size () : num_fns;
 
   /* Consider each candidate in turn.  */
@@ -3073,9 +3049,9 @@ find_oload_champ (gdb::array_view<value *> args,
       bv = rank_function (parm_types,
 			  args.slice (static_offset));
 
-      if (!*oload_champ_bv)
+      if (oload_champ_bv->empty ())
 	{
-	  *oload_champ_bv = bv;
+	  *oload_champ_bv = std::move (bv);
 	  oload_champ = 0;
 	}
       else /* See whether current candidate is better or worse than
@@ -3089,7 +3065,7 @@ find_oload_champ (gdb::array_view<value *> args,
 	    oload_ambiguous = 2;
 	    break;
 	  case 2:		/* New champion, record details.  */
-	    *oload_champ_bv = bv;
+	    *oload_champ_bv = std::move (bv);
 	    oload_ambiguous = 0;
 	    oload_champ = ix;
 	    break;
@@ -3116,7 +3092,7 @@ find_oload_champ (gdb::array_view<value *> args,
 	  for (jj = 0; jj < args.size () - static_offset; jj++)
 	    fprintf_filtered (gdb_stderr,
 			      "...Badness @ %d : %d\n", 
-			      jj, bv->rank[jj].rank);
+			      jj, bv[jj].rank);
 	  fprintf_filtered (gdb_stderr, "Overload resolution "
 			    "champion is %d, ambiguous? %d\n", 
 			    oload_champ, oload_ambiguous);
@@ -3141,7 +3117,7 @@ oload_method_static_p (struct fn_field *fns_ptr, int index)
 /* Check how good an overload match OLOAD_CHAMP_BV represents.  */
 
 static enum oload_classification
-classify_oload_match (struct badness_vector *oload_champ_bv,
+classify_oload_match (const badness_vector &oload_champ_bv,
 		      int nargs,
 		      int static_offset)
 {
@@ -3152,12 +3128,12 @@ classify_oload_match (struct badness_vector *oload_champ_bv,
     {
       /* If this conversion is as bad as INCOMPATIBLE_TYPE_BADNESS
          or worse return INCOMPATIBLE.  */
-      if (compare_ranks (oload_champ_bv->rank[ix],
+      if (compare_ranks (oload_champ_bv[ix],
                          INCOMPATIBLE_TYPE_BADNESS) <= 0)
 	return INCOMPATIBLE;	/* Truly mismatched types.  */
       /* Otherwise If this conversion is as bad as
          NS_POINTER_CONVERSION_BADNESS or worse return NON_STANDARD.  */
-      else if (compare_ranks (oload_champ_bv->rank[ix],
+      else if (compare_ranks (oload_champ_bv[ix],
                               NS_POINTER_CONVERSION_BADNESS) <= 0)
 	worst = NON_STANDARD;	/* Non-standard type conversions
 				   needed.  */
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/6] invoke_xmethod & array_view
  2018-10-17 16:21   ` Simon Marchi
@ 2018-11-21 12:47     ` Pedro Alves
  2018-11-26 17:18       ` Simon Marchi
  0 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2018-11-21 12:47 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 10/17/2018 05:21 PM, Simon Marchi wrote:
> On 2018-10-15 11:11 a.m., Pedro Alves wrote:
>> This replaces more pointer+length with gdb::array_view.  This time,
>> around invoke_xmethod, and then propagating the fallout around, which
>> inevitably leads to the overload resolution code.
>>
>> There are several places in the code that want to grab a slice of an
>> array, by advanting the array pointer, and decreasing the length
> 
> "advanting"

Fixed.

> 
>> pointer.  This patch introduces a pair of new
>> gdb::array_view::slice(...) methods to make that convenient and clear.
>> Unit test included.
> 
> Cool!
> 
> Just some minor comments.
> 
> I noticed some lines > 80 columns:
> 
> $ git show | grep ^\+ | tr '\t' '        ' | egrep '.{81}'
> +      return call_xmethod (argvec[0], gdb::make_array_view (argvec + 1, nargs));
> +value_user_defined_op (struct value **argp, gdb::array_view<value *> args, char *name,
> +      && classify_oload_match (new_oload_champ_bv, args.size (), 0) == STANDARD)
> 

Fixed the middle one, thanks.  The others are actually at 80 cols.

> 
>> diff --git a/gdb/common/array-view.h b/gdb/common/array-view.h
>> index 45d1a4720e..679d2e95c7 100644
>> --- a/gdb/common/array-view.h
>> +++ b/gdb/common/array-view.h
>> @@ -169,6 +169,17 @@ public:
>>    constexpr size_type size () const noexcept { return m_size; }
>>    constexpr bool empty () const noexcept { return m_size == 0; }
>>  
>> +  /* Slice an array view.  */
>> +
>> +  /* Return a new array view over SIZE elements starting at START.  */
>> +  constexpr array_view<T> slice (size_type start, size_t size) const noexcept
>> +  { return {m_array + start, size}; }
> 
> I'm sure there's a logic for using size_type for one parameter and size_t for the other
> (instead of size_type for both), but what is it?

There's no logic, just some copy&pasting&editing, I guess.

> 
>> +
>> +  /* Return a new array view over all the elements after START,
>> +     inclusive.  */
>> +  constexpr array_view<T> slice (size_type start) const noexcept
>> +  { return {m_array + start, size () - start}; }
> 
> It would perhaps be good to have some asserts (that are only there in development
> mode, maybe) to make sure we don't do stupid things, like take a slice
> past the end of the array, things like that.  A bit like those asserts enabled by
> __GLIBCXX_DEBUG.

Doing it in development mode might be useful.  In that case, it would
better be done to e.g., operator[] too, I think.  Also, not sure we
already have a development vs release preprocessor macro?
Thus I'd rather see it in a separate patch.

> 
>> diff --git a/gdb/extension.h b/gdb/extension.h
>> index 0c8c4ee934..4716d6f360 100644
>> --- a/gdb/extension.h
>> +++ b/gdb/extension.h
>> @@ -22,6 +22,7 @@
>>  
>>  #include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc.  */
>>  #include "common/vec.h"
>> +#include "common/array-view.h"
>>  
>>  struct breakpoint;
>>  struct command_line;
>> @@ -186,38 +187,35 @@ struct xmethod_worker
>>    virtual ~xmethod_worker () = default;
>>  
>>    /* Invoke the xmethod encapsulated in this worker and return the result.
>> -     The method is invoked on OBJ with arguments in the ARGS array.  NARGS is
>> -     the length of the this array.  */
>> +     The method is invoked on OBJ with arguments in the ARGS array.  */
>>  
>> -  virtual value *invoke (value *obj, value **args, int nargs) = 0;
>> +  virtual value *invoke (value *obj, gdb::array_view<value *> args) = 0;
>>  
>>    /* Return the arg types of the xmethod encapsulated in this worker.
>> -     An array of arg types is returned.  The length of the array is returned in
>> -     NARGS.  The type of the 'this' object is returned as the first element of
>> -     array.  */
>> +     The type of the 'this' object is returned as the first element of
>> +     the vector.  */
>>  
>> -  type **get_arg_types (int *nargs);
>> +  std::vector<type *> get_arg_types ();
>>  
>>    /* Return the type of the result of the xmethod encapsulated in this worker.
>> -     OBJECT, ARGS, NARGS are the same as for invoke.  */
>> +     OBJECT and ARGS are the same as for invoke.  */
>>  
>> -  type *get_result_type (value *object, value **args, int nargs);
>> +  type *get_result_type (value *object, gdb::array_view<value *> args);
>>  
>>  private:
>>  
>> -  /* Return the types of the arguments the method takes.  The number of
>> -     arguments is returned in NARGS, and their types are returned in the array
>> -     ARGTYPES.  */
>> +  /* Return the types of the arguments the method takes.  The types
>> +     are returned in TYPE_ARGS, one per argument.  */
>>  
>>    virtual enum ext_lang_rc do_get_arg_types
>> -    (int *nargs, struct type ***arg_types) = 0;
>> +    (std::vector<type *> &type_args) = 0;
> 
> Could you change this to be a pointer to the std::vector?
> 
> https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Avoid_non-const_reference_parameters.2C_use_pointers_instead
> 

I changed it, though I'm not a big fan of that rule.  

As I wrote at <https://gcc.gnu.org/ml/gcc/2018-07/msg00190.html>, I used to
prefer avoiding non-const reference output parameters too back in my
earlier C++ days, but I no longer do so much nowadays.

The main point of avoiding non-const reference parameters is that
supposedly they make function callers unclearer, with no
visual indication that the function modified the argument.  The
idea is that "&foo" instead of "foo" is that visual distinction.
But, that point can easily become moot because the visual distinction
can be easily lost with pointers too:

 // the usual argument is that using pointers for output parameters shows
 // clearly that bar is going to be modified:
 function (foo, &bar);

 // but well, we often works with pointers, and if "bar" is a pointer,
 // we don't get any visual clue anyway either:
 function (foo, bar);

 // which suggests that what really helps is seeing the output
 // variable nearby, suggesting to define it right before the
 // function call that fills it in, and I would go as far
 // as saying that clearer symbol names help even more.  For e.g.:
 B bar_out;
 fill_bar (foo, bar_out);

I think that symbol and function naming above is much more important
than "&bar" vs "bar".  A function called "fill_bar" is clearly going
to write to its "bar_out" argument.

Also, a pointer can be null, while a reference can not.  So
a reference parameter automatically implies that you can't pass
a NULL pointer to the function (which makes the function's
implementation a little bit clearer too), while with a pointer parameter
you have to document that, and maybe assert it.  With a reference, the
compiler is free to optimize accordingly (assume non-null), while with
a pointer, you have to use gcc's attribute nonnull if you want that,
which no one does.

Also, for std::vector parameters in particular, passing by pointer
leads to uglier code in the function's implementation, like e.g.,

 (*vec)[idx] = 0;

instead of:

 vec[idx] = 0;

We end up with a few instances like that in the series, though admittedly
not that many, otherwise I think I'd add something like:

  auto &vec = *vec_param;

at the top of the function and then use vec throughout.

So in sum, I nowadays tend to look at reference vs parameter more from
the "pointer: optional, can be NULL", vs "reference: non-optional" angle.
Though, given GDB's history, we definetely use pointers pervasively
in function parameters even when they're not supposed to be optional,
that's for sure.

Maybe we could come up with some middle ground rule, like always
putting in-out and output parameters last, and stressing to use
clear symbol names.

Anyway, I don't want to block on that discussion (my 1 month round trip
time not helping! :-D), so I did the change.

>> @@ -312,19 +312,19 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *oper,
>>     function, otherwise return NULL.  */
>>  
>>  static struct value *
>> -value_user_defined_op (struct value **argp, struct value **args, char *name,
>> -                       int *static_memfuncp, int nargs, enum noside noside)
>> +value_user_defined_op (struct value **argp, gdb::array_view<value *> args, char *name,
>> +		       int *static_memfuncp, enum noside noside)
>>  {
>>    struct value *result = NULL;
>>  
>>    if (current_language->la_language == language_cplus)
>>      {
>> -      result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp,
>> +      result = value_user_defined_cpp_op (args, name, static_memfuncp,
>>  					  noside);
>>      }
> 
> Maybe remove the extra braces, while touching this.

This is from <https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Whitespaces>:

 "Any two or more lines in code should be wrapped in braces, even if they are comments, as they look like separate statements: "


Here's what I merged.

From 6b1747cd135ff9859fceb6043179b1ef94363996 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 21 Nov 2018 11:55:12 +0000
Subject: [PATCH 2/6] invoke_xmethod & array_view

This replaces more pointer+length with gdb::array_view.  This time,
around invoke_xmethod, and then propagating the fallout around, which
inevitably leaks to the overload resolution code.

There are several places in the code that want to grab a slice of an
array, by advancing the array pointer, and decreasing the length
pointer.  This patch introduces a pair of new
gdb::array_view::slice(...) methods to make that convenient and clear.
Unit test included.

gdb/ChangeLog:
2018-11-21  Pedro Alves  <palves@redhat.com>

	* common/array-view.h (array_view::splice(size_type, size_t)): New.
	(array_view::splice(size_type)): New.
	* eval.c (eval_call, evaluate_funcall): Adjust to use array_view.
	* extension.c (xmethod_worker::get_arg_types): Adjust to return an
	std::vector.
	(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
	* extension.h: Include "common/array-view.h".
	(xmethod_worker::invoke): Adjust to use gdb::array_view.
	(xmethod_worker::get_arg_types): Adjust to return an std::vector.
	(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
	(xmethod_worker::do_get_arg_types): Adjust to use std::vector.
	(xmethod_worker::do_get_result_type): Adjust to use
	gdb::array_view.
	* gdbtypes.c (rank_function): Adjust to use gdb::array_view.
	* gdbtypes.h: Include "common/array-view.h".
	(rank_function): Adjust to use gdb::array_view.
	* python/py-xmethods.c (python_xmethod_worker::invoke)
	(python_xmethod_worker::do_get_arg_types)
	(python_xmethod_worker::do_get_result_type)
	(python_xmethod_worker::invoke): Adjust to new interfaces.
	* valarith.c (value_user_defined_cpp_op, value_user_defined_op)
	(value_x_binop, value_x_unop): Adjust to use gdb::array_view.
	* valops.c (find_overload_match, find_oload_champ_namespace)
	(find_oload_champ_namespace_loop, find_oload_champ): Adjust to use
	gdb:array_view and the new xmethod_worker interfaces.
	* value.c (result_type_of_xmethod, call_xmethod): Adjust to use
	gdb::array_view.
	* value.h (find_overload_match, result_type_of_xmethod)
	(call_xmethod): Adjust to use gdb::array_view.
	* unittests/array-view-selftests.c: Add slicing tests.
---
 gdb/ChangeLog                        |  33 +++++++++++
 gdb/common/array-view.h              |  11 ++++
 gdb/eval.c                           |  14 +++--
 gdb/extension.c                      |  12 ++--
 gdb/extension.h                      |  32 +++++------
 gdb/gdbtypes.c                       |  21 ++++---
 gdb/gdbtypes.h                       |   5 +-
 gdb/python/py-xmethods.c             |  40 ++++++--------
 gdb/unittests/array-view-selftests.c |  22 ++++++++
 gdb/valarith.c                       |  50 ++++++++---------
 gdb/valops.c                         | 104 +++++++++++++++++------------------
 gdb/value.c                          |  13 ++---
 gdb/value.h                          |   6 +-
 13 files changed, 212 insertions(+), 151 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e315f34dc1..27da6431b3 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,36 @@
+2018-11-21  Pedro Alves  <palves@redhat.com>
+
+	* common/array-view.h (array_view::splice(size_type, size_t)): New.
+	(array_view::splice(size_type)): New.
+	* eval.c (eval_call, evaluate_funcall): Adjust to use array_view.
+	* extension.c (xmethod_worker::get_arg_types): Adjust to return an
+	std::vector.
+	(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
+	* extension.h: Include "common/array-view.h".
+	(xmethod_worker::invoke): Adjust to use gdb::array_view.
+	(xmethod_worker::get_arg_types): Adjust to return an std::vector.
+	(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
+	(xmethod_worker::do_get_arg_types): Adjust to use std::vector.
+	(xmethod_worker::do_get_result_type): Adjust to use
+	gdb::array_view.
+	* gdbtypes.c (rank_function): Adjust to use gdb::array_view.
+	* gdbtypes.h: Include "common/array-view.h".
+	(rank_function): Adjust to use gdb::array_view.
+	* python/py-xmethods.c (python_xmethod_worker::invoke)
+	(python_xmethod_worker::do_get_arg_types)
+	(python_xmethod_worker::do_get_result_type)
+	(python_xmethod_worker::invoke): Adjust to new interfaces.
+	* valarith.c (value_user_defined_cpp_op, value_user_defined_op)
+	(value_x_binop, value_x_unop): Adjust to use gdb::array_view.
+	* valops.c (find_overload_match, find_oload_champ_namespace)
+	(find_oload_champ_namespace_loop, find_oload_champ): Adjust to use
+	gdb:array_view and the new xmethod_worker interfaces.
+	* value.c (result_type_of_xmethod, call_xmethod): Adjust to use
+	gdb::array_view.
+	* value.h (find_overload_match, result_type_of_xmethod)
+	(call_xmethod): Adjust to use gdb::array_view.
+	* unittests/array-view-selftests.c: Add slicing tests.
+
 2018-11-21  Pedro Alves  <palves@redhat.com>
 
 	* ada-lang.c (ada_evaluate_subexp): Adjust to pass an array_view.
diff --git a/gdb/common/array-view.h b/gdb/common/array-view.h
index 9c5fa2a971..d7293c7c5f 100644
--- a/gdb/common/array-view.h
+++ b/gdb/common/array-view.h
@@ -169,6 +169,17 @@ public:
   constexpr size_type size () const noexcept { return m_size; }
   constexpr bool empty () const noexcept { return m_size == 0; }
 
+  /* Slice an array view.  */
+
+  /* Return a new array view over SIZE elements starting at START.  */
+  constexpr array_view<T> slice (size_type start, size_type size) const noexcept
+  { return {m_array + start, size}; }
+
+  /* Return a new array view over all the elements after START,
+     inclusive.  */
+  constexpr array_view<T> slice (size_type start) const noexcept
+  { return {m_array + start, size () - start}; }
+
 private:
   T *m_array;
   size_type m_size;
diff --git a/gdb/eval.c b/gdb/eval.c
index 6eb210d109..cb408678a2 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -789,7 +789,9 @@ eval_call (expression *exp, enum noside noside,
       else if (TYPE_CODE (ftype) == TYPE_CODE_XMETHOD)
 	{
 	  type *return_type
-	    = result_type_of_xmethod (argvec[0], nargs, argvec + 1);
+	    = result_type_of_xmethod (argvec[0],
+				      gdb::make_array_view (argvec + 1,
+							    nargs));
 
 	  if (return_type == NULL)
 	    error (_("Xmethod is missing return type."));
@@ -827,7 +829,7 @@ eval_call (expression *exp, enum noside noside,
       return call_internal_function (exp->gdbarch, exp->language_defn,
 				     argvec[0], nargs, argvec + 1);
     case TYPE_CODE_XMETHOD:
-      return call_xmethod (argvec[0], nargs, argvec + 1);
+      return call_xmethod (argvec[0], gdb::make_array_view (argvec + 1, nargs));
     default:
       return call_function_by_hand (argvec[0], default_return_type,
 				    gdb::make_array_view (argvec + 1, nargs));
@@ -1100,7 +1102,8 @@ evaluate_funcall (type *expect_type, expression *exp, int *pos,
       func_name = (char *) alloca (name_len + 1);
       strcpy (func_name, &exp->elts[string_pc + 1].string);
 
-      find_overload_match (&argvec[1], nargs, func_name,
+      find_overload_match (gdb::make_array_view (&argvec[1], nargs),
+			   func_name,
 			   NON_METHOD, /* not method */
 			   NULL, NULL, /* pass NULL symbol since
 					  symbol is unknown */
@@ -1136,7 +1139,8 @@ evaluate_funcall (type *expect_type, expression *exp, int *pos,
 	     evaluation.  */
 	  struct value *valp = NULL;
 
-	  (void) find_overload_match (&argvec[1], nargs, tstr,
+	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
+				      tstr,
 				      METHOD, /* method */
 				      &arg2,  /* the object */
 				      NULL, &valp, NULL,
@@ -1207,7 +1211,7 @@ evaluate_funcall (type *expect_type, expression *exp, int *pos,
 	  if (op == OP_VAR_VALUE)
 	    function = exp->elts[save_pos1+2].symbol;
 
-	  (void) find_overload_match (&argvec[1], nargs,
+	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
 				      NULL,        /* no need for name */
 				      NON_METHOD,  /* not method */
 				      NULL, function, /* the function */
diff --git a/gdb/extension.c b/gdb/extension.c
index e5c014667a..31d19b5b09 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -870,12 +870,12 @@ get_matching_xmethod_workers (struct type *type, const char *method_name,
 
 /* See extension.h.  */
 
-type **
-xmethod_worker::get_arg_types (int *nargs)
+std::vector<type *>
+xmethod_worker::get_arg_types ()
 {
-  type **type_array = NULL;
+  std::vector<type *> type_array;
 
-  ext_lang_rc rc = do_get_arg_types (nargs, &type_array);
+  ext_lang_rc rc = do_get_arg_types (&type_array);
   if (rc == EXT_LANG_RC_ERROR)
     error (_("Error while looking for arg types of a xmethod worker "
 	     "defined in %s."), m_extlang->capitalized_name);
@@ -886,11 +886,11 @@ xmethod_worker::get_arg_types (int *nargs)
 /* See extension.h.  */
 
 struct type *
-xmethod_worker::get_result_type (value *object, value **args, int nargs)
+xmethod_worker::get_result_type (value *object, gdb::array_view<value *> args)
 {
   type *result_type;
 
-  ext_lang_rc rc = do_get_result_type (object, args, nargs, &result_type);
+  ext_lang_rc rc = do_get_result_type (object, args, &result_type);
   if (rc == EXT_LANG_RC_ERROR)
     {
       error (_("Error while fetching result type of an xmethod worker "
diff --git a/gdb/extension.h b/gdb/extension.h
index 0c8c4ee934..b9314c0efb 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -22,6 +22,7 @@
 
 #include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc.  */
 #include "common/vec.h"
+#include "common/array-view.h"
 
 struct breakpoint;
 struct command_line;
@@ -186,38 +187,35 @@ struct xmethod_worker
   virtual ~xmethod_worker () = default;
 
   /* Invoke the xmethod encapsulated in this worker and return the result.
-     The method is invoked on OBJ with arguments in the ARGS array.  NARGS is
-     the length of the this array.  */
+     The method is invoked on OBJ with arguments in the ARGS array.  */
 
-  virtual value *invoke (value *obj, value **args, int nargs) = 0;
+  virtual value *invoke (value *obj, gdb::array_view<value *> args) = 0;
 
   /* Return the arg types of the xmethod encapsulated in this worker.
-     An array of arg types is returned.  The length of the array is returned in
-     NARGS.  The type of the 'this' object is returned as the first element of
-     array.  */
+     The type of the 'this' object is returned as the first element of
+     the vector.  */
 
-  type **get_arg_types (int *nargs);
+  std::vector<type *> get_arg_types ();
 
   /* Return the type of the result of the xmethod encapsulated in this worker.
-     OBJECT, ARGS, NARGS are the same as for invoke.  */
+     OBJECT and ARGS are the same as for invoke.  */
 
-  type *get_result_type (value *object, value **args, int nargs);
+  type *get_result_type (value *object, gdb::array_view<value *> args);
 
 private:
 
-  /* Return the types of the arguments the method takes.  The number of
-     arguments is returned in NARGS, and their types are returned in the array
-     ARGTYPES.  */
+  /* Return the types of the arguments the method takes.  The types
+     are returned in TYPE_ARGS, one per argument.  */
 
   virtual enum ext_lang_rc do_get_arg_types
-    (int *nargs, struct type ***arg_types) = 0;
+    (std::vector<type *> *type_args) = 0;
 
-  /* Fetch the type of the result of the method implemented by this worker.
-     OBJECT, ARGS, NARGS are the same as for the invoked method.  The result
-     type is stored in *RESULT_TYPE.  */
+  /* Fetch the type of the result of the method implemented by this
+     worker.  OBJECT and ARGS are the same as for the invoked method.
+     The result type is stored in *RESULT_TYPE.  */
 
   virtual enum ext_lang_rc do_get_result_type
-    (struct value *obj, struct value **args, int nargs,
+    (struct value *obj, gdb::array_view<value *> args,
      struct type **result_type_ptr) = 0;
 
   /* The language the xmethod worker is implemented in.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 9e87b8f4c5..4160d996de 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3464,21 +3464,20 @@ compare_badness (struct badness_vector *a, struct badness_vector *b)
     }
 }
 
-/* Rank a function by comparing its parameter types (PARMS, length
-   NPARMS), to the types of an argument list (ARGS, length NARGS).
-   Return a pointer to a badness vector.  This has NARGS + 1
-   entries.  */
+/* Rank a function by comparing its parameter types (PARMS), to the
+   types of an argument list (ARGS).  Return a pointer to a badness
+   vector.  This has ARGS.size() + 1 entries.  */
 
 struct badness_vector *
-rank_function (struct type **parms, int nparms, 
-	       struct value **args, int nargs)
+rank_function (gdb::array_view<type *> parms,
+	       gdb::array_view<value *> args)
 {
   int i;
   struct badness_vector *bv = XNEW (struct badness_vector);
-  int min_len = nparms < nargs ? nparms : nargs;
+  size_t min_len = std::min (parms.size (), args.size ());
 
-  bv->length = nargs + 1;	/* add 1 for the length-match rank.  */
-  bv->rank = XNEWVEC (struct rank, nargs + 1);
+  bv->length = args.size () + 1;	/* add 1 for the length-match rank.  */
+  bv->rank = XNEWVEC (struct rank, args.size () + 1);
 
   /* First compare the lengths of the supplied lists.
      If there is a mismatch, set it to a high value.  */
@@ -3487,7 +3486,7 @@ rank_function (struct type **parms, int nparms,
      arguments and ellipsis parameter lists, we should consider those
      and rank the length-match more finely.  */
 
-  LENGTH_MATCH (bv) = (nargs != nparms)
+  LENGTH_MATCH (bv) = (args.size () != parms.size ())
 		      ? LENGTH_MISMATCH_BADNESS
 		      : EXACT_MATCH_BADNESS;
 
@@ -3497,7 +3496,7 @@ rank_function (struct type **parms, int nparms,
 				 args[i - 1]);
 
   /* If more arguments than parameters, add dummy entries.  */
-  for (i = min_len + 1; i <= nargs; i++)
+  for (i = min_len + 1; i <= args.size (); i++)
     bv->rank[i] = TOO_FEW_PARAMS_BADNESS;
 
   return bv;
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index a115857c0a..731b18d082 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -45,6 +45,7 @@
  */
 
 #include "hashtab.h"
+#include "common/array-view.h"
 #include "common/offset-type.h"
 #include "common/enum-flags.h"
 #include "common/underlying.h"
@@ -2044,8 +2045,8 @@ extern int compare_ranks (struct rank a, struct rank b);
 
 extern int compare_badness (struct badness_vector *, struct badness_vector *);
 
-extern struct badness_vector *rank_function (struct type **, int,
-					     struct value **, int);
+extern struct badness_vector *rank_function (gdb::array_view<type *> parms,
+					     gdb::array_view<value *> args);
 
 extern struct rank rank_one_type (struct type *, struct type *,
 				  struct value *);
diff --git a/gdb/python/py-xmethods.c b/gdb/python/py-xmethods.c
index 8e616cd4e2..1c96b585f7 100644
--- a/gdb/python/py-xmethods.c
+++ b/gdb/python/py-xmethods.c
@@ -46,11 +46,11 @@ struct python_xmethod_worker : xmethod_worker
 
   /* Implementation of xmethod_worker::invoke for Python.  */
 
-  value *invoke (value *obj, value **args, int nargs) override;
+  value *invoke (value *obj, gdb::array_view<value *> args) override;
 
   /* Implementation of xmethod_worker::do_get_arg_types for Python.  */
 
-  ext_lang_rc do_get_arg_types (int *nargs, type ***arg_types) override;
+  ext_lang_rc do_get_arg_types (std::vector<type *> *type_args) override;
 
   /* Implementation of xmethod_worker::do_get_result_type for Python.
 
@@ -58,7 +58,7 @@ struct python_xmethod_worker : xmethod_worker
      result type, if the get_result_type operation is not provided by WORKER
      then EXT_LANG_RC_OK is returned and NULL is returned in *RESULT_TYPE.  */
 
-  ext_lang_rc do_get_result_type (value *obj, value **args, int nargs,
+  ext_lang_rc do_get_result_type (value *obj, gdb::array_view<value *> args,
 				  type **result_type_ptr) override;
 
 private:
@@ -293,7 +293,7 @@ gdbpy_get_matching_xmethod_workers
 /* See declaration.  */
 
 ext_lang_rc
-python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
+python_xmethod_worker::do_get_arg_types (std::vector<type *> *arg_types)
 {
   /* The gdbpy_enter object needs to be placed first, so that it's the last to
      be destroyed.  */
@@ -302,10 +302,6 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
   int i = 1, arg_count;
   gdbpy_ref<> list_iter;
 
-  /* Set nargs to -1 so that any premature return from this function returns
-     an invalid/unusable number of arg types.  */
-  *nargs = -1;
-
   gdbpy_ref<> get_arg_types_method
     (PyObject_GetAttrString (m_py_worker, get_arg_types_method_name));
   if (get_arg_types_method == NULL)
@@ -345,8 +341,7 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
     arg_count = 1;
 
   /* Include the 'this' argument in the size.  */
-  gdb::unique_xmalloc_ptr<struct type *> type_array
-    (XCNEWVEC (struct type *, arg_count + 1));
+  arg_types->resize (arg_count + 1);
   i = 1;
   if (list_iter != NULL)
     {
@@ -373,7 +368,7 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
 	      return EXT_LANG_RC_ERROR;
 	    }
 
-	  (type_array.get ())[i] = arg_type;
+	  (*arg_types)[i] = arg_type;
 	  i++;
 	}
     }
@@ -393,7 +388,7 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
 	}
       else
 	{
-	  (type_array.get ())[i] = arg_type;
+	  (*arg_types)[i] = arg_type;
 	  i++;
 	}
     }
@@ -402,10 +397,8 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
      be a 'const' value.  Hence, create a 'const' variant of the 'this' pointer
      type.  */
   obj_type = type_object_to_type (m_this_type);
-  (type_array.get ())[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type),
-					 NULL);
-  *nargs = i;
-  *arg_types = type_array.release ();
+  (*arg_types)[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type),
+				  NULL);
 
   return EXT_LANG_RC_OK;
 }
@@ -413,7 +406,8 @@ python_xmethod_worker::do_get_arg_types (int *nargs, type ***arg_types)
 /* See declaration.  */
 
 ext_lang_rc
-python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
+python_xmethod_worker::do_get_result_type (value *obj,
+					   gdb::array_view<value *> args,
 					   type **result_type_ptr)
 {
   struct type *obj_type, *this_type;
@@ -461,7 +455,7 @@ python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
       return EXT_LANG_RC_ERROR;
     }
 
-  gdbpy_ref<> py_arg_tuple (PyTuple_New (nargs + 1));
+  gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
   if (py_arg_tuple == NULL)
     {
       gdbpy_print_stack ();
@@ -472,7 +466,7 @@ python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
      release.  */
   PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
 
-  for (i = 0; i < nargs; i++)
+  for (i = 0; i < args.size (); i++)
     {
       PyObject *py_value_arg = value_to_value_object (args[i]);
 
@@ -508,8 +502,8 @@ python_xmethod_worker::do_get_result_type (value *obj, value **args, int nargs,
 /* See declaration.  */
 
 struct value *
-python_xmethod_worker::invoke (struct value *obj, struct value **args,
-			       int nargs)
+python_xmethod_worker::invoke (struct value *obj,
+			       gdb::array_view<value *> args)
 {
   gdbpy_enter enter_py (get_current_arch (), current_language);
 
@@ -546,7 +540,7 @@ python_xmethod_worker::invoke (struct value *obj, struct value **args,
       error (_("Error while executing Python code."));
     }
 
-  gdbpy_ref<> py_arg_tuple (PyTuple_New (nargs + 1));
+  gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
   if (py_arg_tuple == NULL)
     {
       gdbpy_print_stack ();
@@ -557,7 +551,7 @@ python_xmethod_worker::invoke (struct value *obj, struct value **args,
      release.  */
   PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
 
-  for (i = 0; i < nargs; i++)
+  for (i = 0; i < args.size (); i++)
     {
       PyObject *py_value_arg = value_to_value_object (args[i]);
 
diff --git a/gdb/unittests/array-view-selftests.c b/gdb/unittests/array-view-selftests.c
index 74defa1b40..746062c75a 100644
--- a/gdb/unittests/array-view-selftests.c
+++ b/gdb/unittests/array-view-selftests.c
@@ -496,6 +496,28 @@ run_tests ()
     for (size_t i = 0; i < len; i++)
       SELF_CHECK (view[i] == data[i]);
   }
+
+  /* Test slicing.  */
+  {
+    gdb_byte data[] = {0x55, 0x66, 0x77, 0x88, 0x99};
+    gdb::array_view<gdb_byte> view = data;
+
+    {
+      auto slc = view.slice (1, 3);
+      SELF_CHECK (slc.data () == data + 1);
+      SELF_CHECK (slc.size () == 3);
+      SELF_CHECK (slc[0] == data[1]);
+      SELF_CHECK (slc[0] == view[1]);
+    }
+
+    {
+      auto slc = view.slice (2);
+      SELF_CHECK (slc.data () == data + 2);
+      SELF_CHECK (slc.size () == 3);
+      SELF_CHECK (slc[0] == view[2]);
+      SELF_CHECK (slc[0] == data[2]);
+    }
+  }
 }
 
 } /* namespace array_view_tests */
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 875f5477c2..3a59ada2d5 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -281,14 +281,14 @@ unop_user_defined_p (enum exp_opcode op, struct value *arg1)
    situations or combinations thereof.  */
 
 static struct value *
-value_user_defined_cpp_op (struct value **args, int nargs, char *oper,
+value_user_defined_cpp_op (gdb::array_view<value *> args, char *oper,
                            int *static_memfuncp, enum noside noside)
 {
 
   struct symbol *symp = NULL;
   struct value *valp = NULL;
 
-  find_overload_match (args, nargs, oper, BOTH /* could be method */,
+  find_overload_match (args, oper, BOTH /* could be method */,
                        &args[0] /* objp */,
                        NULL /* pass NULL symbol since symbol is unknown */,
                        &valp, &symp, static_memfuncp, 0, noside);
@@ -312,19 +312,19 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *oper,
    function, otherwise return NULL.  */
 
 static struct value *
-value_user_defined_op (struct value **argp, struct value **args, char *name,
-                       int *static_memfuncp, int nargs, enum noside noside)
+value_user_defined_op (struct value **argp, gdb::array_view<value *> args,
+		       char *name, int *static_memfuncp, enum noside noside)
 {
   struct value *result = NULL;
 
   if (current_language->la_language == language_cplus)
     {
-      result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp,
+      result = value_user_defined_cpp_op (args, name, static_memfuncp,
 					  noside);
     }
   else
-    result = value_struct_elt (argp, args, name, static_memfuncp,
-                               "structure");
+    result = value_struct_elt (argp, args.data (), name, static_memfuncp,
+			       "structure");
 
   return result;
 }
@@ -342,7 +342,6 @@ struct value *
 value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	       enum exp_opcode otherop, enum noside noside)
 {
-  struct value **argvec;
   char *ptr;
   char tstr[13];
   int static_memfuncp;
@@ -356,10 +355,11 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
   if (TYPE_CODE (check_typedef (value_type (arg1))) != TYPE_CODE_STRUCT)
     error (_("Can't do that binary op on that type"));	/* FIXME be explicit */
 
-  argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+  value *argvec_storage[3];
+  gdb::array_view<value *> argvec = argvec_storage;
+
   argvec[1] = value_addr (arg1);
   argvec[2] = arg2;
-  argvec[3] = 0;
 
   /* Make the right function name up.  */
   strcpy (tstr, "operator__");
@@ -469,15 +469,15 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
       error (_("Invalid binary operation specified."));
     }
 
-  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
-                                     &static_memfuncp, 2, noside);
+  argvec[0] = value_user_defined_op (&arg1, argvec.slice (1), tstr,
+				     &static_memfuncp, noside);
 
   if (argvec[0])
     {
       if (static_memfuncp)
 	{
 	  argvec[1] = argvec[0];
-	  argvec++;
+	  argvec = argvec.slice (1);
 	}
       if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_XMETHOD)
 	{
@@ -486,13 +486,13 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	    {
 	      struct type *return_type
-		= result_type_of_xmethod (argvec[0], 2, argvec + 1);
+		= result_type_of_xmethod (argvec[0], argvec.slice (1));
 
 	      if (return_type == NULL)
 		error (_("Xmethod is missing return type."));
 	      return value_zero (return_type, VALUE_LVAL (arg1));
 	    }
-	  return call_xmethod (argvec[0], 2, argvec + 1);
+	  return call_xmethod (argvec[0], argvec.slice (1));
 	}
       if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	{
@@ -503,7 +503,7 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
       return call_function_by_hand (argvec[0], NULL,
-				    {argvec + 1, 2u - static_memfuncp});
+				    argvec.slice (1, 2 - static_memfuncp));
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
@@ -519,7 +519,6 @@ struct value *
 value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 {
   struct gdbarch *gdbarch = get_type_arch (value_type (arg1));
-  struct value **argvec;
   char *ptr;
   char tstr[13], mangle_tstr[13];
   int static_memfuncp, nargs;
@@ -532,7 +531,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
   if (TYPE_CODE (check_typedef (value_type (arg1))) != TYPE_CODE_STRUCT)
     error (_("Can't do that unary op on that type"));	/* FIXME be explicit */
 
-  argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+  value *argvec_storage[3];
+  gdb::array_view<value *> argvec = argvec_storage;
+
   argvec[1] = value_addr (arg1);
   argvec[2] = 0;
 
@@ -584,16 +585,15 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
       error (_("Invalid unary operation specified."));
     }
 
-  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
-                                     &static_memfuncp, nargs, noside);
+  argvec[0] = value_user_defined_op (&arg1, argvec.slice (1, nargs), tstr,
+				     &static_memfuncp, noside);
 
   if (argvec[0])
     {
       if (static_memfuncp)
 	{
 	  argvec[1] = argvec[0];
-	  nargs --;
-	  argvec++;
+	  argvec = argvec.slice (1);
 	}
       if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_XMETHOD)
 	{
@@ -602,13 +602,13 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	    {
 	      struct type *return_type
-		= result_type_of_xmethod (argvec[0], 1, argvec + 1);
+		= result_type_of_xmethod (argvec[0], argvec[1]);
 
 	      if (return_type == NULL)
 		error (_("Xmethod is missing return type."));
 	      return value_zero (return_type, VALUE_LVAL (arg1));
 	    }
-	  return call_xmethod (argvec[0], 1, argvec + 1);
+	  return call_xmethod (argvec[0], argvec[1]);
 	}
       if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	{
@@ -619,7 +619,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	  return value_zero (return_type, VALUE_LVAL (arg1));
 	}
       return call_function_by_hand (argvec[0], NULL,
-				    gdb::make_array_view (argvec + 1, nargs));
+				    argvec.slice (1, nargs));
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
diff --git a/gdb/valops.c b/gdb/valops.c
index 4758b5cdfc..f0e53a7ce9 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -54,20 +54,19 @@ static struct value *search_struct_method (const char *, struct value **,
 					   struct value **,
 					   LONGEST, int *, struct type *);
 
-static int find_oload_champ_namespace (struct value **, int,
+static int find_oload_champ_namespace (gdb::array_view<value *> args,
 				       const char *, const char *,
 				       struct symbol ***,
 				       struct badness_vector **,
 				       const int no_adl);
 
-static
-int find_oload_champ_namespace_loop (struct value **, int,
-				     const char *, const char *,
-				     int, struct symbol ***,
-				     struct badness_vector **, int *,
-				     const int no_adl);
+static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
+					    const char *, const char *,
+					    int, struct symbol ***,
+					    struct badness_vector **, int *,
+					    const int no_adl);
 
-static int find_oload_champ (struct value **, int, int,
+static int find_oload_champ (gdb::array_view<value *> args, int,
 			     struct fn_field *,
 			     const std::vector<xmethod_worker_up> *,
 			     struct symbol **, struct badness_vector **);
@@ -2446,11 +2445,11 @@ value_find_oload_method_list (struct value **argp, const char *method,
 		    basetype, boffset);
 }
 
-/* Given an array of arguments (ARGS) (which includes an
-   entry for "this" in the case of C++ methods), the number of
-   arguments NARGS, the NAME of a function, and whether it's a method or
-   not (METHOD), find the best function that matches on the argument types
-   according to the overload resolution rules.
+/* Given an array of arguments (ARGS) (which includes an entry for
+   "this" in the case of C++ methods), the NAME of a function, and
+   whether it's a method or not (METHOD), find the best function that
+   matches on the argument types according to the overload resolution
+   rules.
 
    METHOD can be one of three values:
      NON_METHOD for non-member functions.
@@ -2493,7 +2492,7 @@ value_find_oload_method_list (struct value **argp, const char *method,
    resolution is permitted.  */
 
 int
-find_overload_match (struct value **args, int nargs,
+find_overload_match (gdb::array_view<value *> args,
 		     const char *name, enum oload_search_type method,
 		     struct value **objp, struct symbol *fsym,
 		     struct value **valp, struct symbol **symp, 
@@ -2578,12 +2577,12 @@ find_overload_match (struct value **args, int nargs,
 	{
 	  gdb_assert (TYPE_SELF_TYPE (fns_ptr[0].type) != NULL);
 
-	  src_method_oload_champ = find_oload_champ (args, nargs,
+	  src_method_oload_champ = find_oload_champ (args,
 						     num_fns, fns_ptr, NULL,
 						     NULL, &src_method_badness);
 
 	  src_method_match_quality = classify_oload_match
-	    (src_method_badness, nargs,
+	    (src_method_badness, args.size (),
 	     oload_method_static_p (fns_ptr, src_method_oload_champ));
 
 	  make_cleanup (xfree, src_method_badness);
@@ -2591,11 +2590,10 @@ find_overload_match (struct value **args, int nargs,
 
       if (!xm_worker_vec.empty ())
 	{
-	  ext_method_oload_champ = find_oload_champ (args, nargs,
-						     0, NULL, &xm_worker_vec,
+	  ext_method_oload_champ = find_oload_champ (args, 0, NULL, &xm_worker_vec,
 						     NULL, &ext_method_badness);
 	  ext_method_match_quality = classify_oload_match (ext_method_badness,
-							   nargs, 0);
+							   args.size (), 0);
 	  make_cleanup (xfree, ext_method_badness);
 	}
 
@@ -2708,7 +2706,7 @@ find_overload_match (struct value **args, int nargs,
           return 0;
         }
 
-      func_oload_champ = find_oload_champ_namespace (args, nargs,
+      func_oload_champ = find_oload_champ_namespace (args,
                                                      func_name,
                                                      qualified_name,
                                                      &oload_syms,
@@ -2716,7 +2714,8 @@ find_overload_match (struct value **args, int nargs,
                                                      no_adl);
 
       if (func_oload_champ >= 0)
-	func_match_quality = classify_oload_match (func_badness, nargs, 0);
+	func_match_quality = classify_oload_match (func_badness,
+						   args.size (), 0);
 
       make_cleanup (xfree, oload_syms);
       make_cleanup (xfree, func_badness);
@@ -2855,7 +2854,7 @@ find_overload_match (struct value **args, int nargs,
    performned.  */
 
 static int
-find_oload_champ_namespace (struct value **args, int nargs,
+find_oload_champ_namespace (gdb::array_view<value *> args,
 			    const char *func_name,
 			    const char *qualified_name,
 			    struct symbol ***oload_syms,
@@ -2864,7 +2863,7 @@ find_oload_champ_namespace (struct value **args, int nargs,
 {
   int oload_champ;
 
-  find_oload_champ_namespace_loop (args, nargs,
+  find_oload_champ_namespace_loop (args,
 				   func_name,
 				   qualified_name, 0,
 				   oload_syms, oload_champ_bv,
@@ -2884,7 +2883,7 @@ find_oload_champ_namespace (struct value **args, int nargs,
    *OLOAD_CHAMP_BV.  */
 
 static int
-find_oload_champ_namespace_loop (struct value **args, int nargs,
+find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 				 const char *func_name,
 				 const char *qualified_name,
 				 int namespace_len,
@@ -2921,7 +2920,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
     {
       searched_deeper = 1;
 
-      if (find_oload_champ_namespace_loop (args, nargs,
+      if (find_oload_champ_namespace_loop (args,
 					   func_name, qualified_name,
 					   next_namespace_len,
 					   oload_syms, oload_champ_bv,
@@ -2956,16 +2955,16 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
 
       /* Prepare list of argument types for overload resolution.  */
       arg_types = (struct type **)
-	alloca (nargs * (sizeof (struct type *)));
-      for (ix = 0; ix < nargs; ix++)
+	alloca (args.size () * (sizeof (struct type *)));
+      for (ix = 0; ix < args.size (); ix++)
 	arg_types[ix] = value_type (args[ix]);
-      make_symbol_overload_list_adl (arg_types, nargs, func_name);
+      make_symbol_overload_list_adl (arg_types, args.size (), func_name);
     }
 
   while (new_oload_syms[num_fns])
     ++num_fns;
 
-  new_oload_champ = find_oload_champ (args, nargs, num_fns,
+  new_oload_champ = find_oload_champ (args, num_fns,
 				      NULL, NULL, new_oload_syms,
 				      &new_oload_champ_bv);
 
@@ -2977,7 +2976,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
      it's a bad match.  */
 
   if (new_oload_champ != -1
-      && classify_oload_match (new_oload_champ_bv, nargs, 0) == STANDARD)
+      && classify_oload_match (new_oload_champ_bv, args.size (), 0) == STANDARD)
     {
       *oload_syms = new_oload_syms;
       *oload_champ = new_oload_champ;
@@ -3002,11 +3001,10 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
     }
 }
 
-/* Look for a function to take NARGS args of ARGS.  Find
-   the best match from among the overloaded methods or functions
-   given by FNS_PTR or OLOAD_SYMS or XM_WORKER_VEC, respectively.
-   One, and only one of FNS_PTR, OLOAD_SYMS and XM_WORKER_VEC can be
-   non-NULL.
+/* Look for a function to take ARGS.  Find the best match from among
+   the overloaded methods or functions given by FNS_PTR or OLOAD_SYMS
+   or XM_WORKER_VEC, respectively.  One, and only one of FNS_PTR,
+   OLOAD_SYMS and XM_WORKER_VEC can be non-NULL.
 
    If XM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
    or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
@@ -3017,7 +3015,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
    It is the caller's responsibility to free *OLOAD_CHAMP_BV.  */
 
 static int
-find_oload_champ (struct value **args, int nargs,
+find_oload_champ (gdb::array_view<value *> args,
 		  int num_fns, struct fn_field *fns_ptr,
 		  const std::vector<xmethod_worker_up> *xm_worker_vec,
 		  struct symbol **oload_syms,
@@ -3047,16 +3045,17 @@ find_oload_champ (struct value **args, int nargs,
     {
       int jj;
       int static_offset = 0;
-      int nparms;
-      struct type **parm_types;
+      std::vector<type *> parm_types;
 
       if (xm_worker_vec != NULL)
 	{
 	  xmethod_worker *worker = (*xm_worker_vec)[ix].get ();
-	  parm_types = worker->get_arg_types (&nparms);
+	  parm_types = worker->get_arg_types ();
 	}
       else
 	{
+	  size_t nparms;
+
 	  if (fns_ptr != NULL)
 	    {
 	      nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
@@ -3065,19 +3064,21 @@ find_oload_champ (struct value **args, int nargs,
 	  else
 	    nparms = TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
 
-	  parm_types = XNEWVEC (struct type *, nparms);
+	  parm_types.reserve (nparms);
 	  for (jj = 0; jj < nparms; jj++)
-	    parm_types[jj] = (fns_ptr != NULL
-			      ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
-			      : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
-						 jj));
+	    {
+	      type *t = (fns_ptr != NULL
+			 ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
+			 : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
+					    jj));
+	      parm_types.push_back (t);
+	    }
 	}
 
       /* Compare parameter types to supplied argument types.  Skip
          THIS for static methods.  */
-      bv = rank_function (parm_types, nparms, 
-			  args + static_offset,
-			  nargs - static_offset);
+      bv = rank_function (parm_types,
+			  args.slice (static_offset));
 
       if (!*oload_champ_bv)
 	{
@@ -3103,24 +3104,23 @@ find_oload_champ (struct value **args, int nargs,
 	  default:
 	    break;
 	  }
-      xfree (parm_types);
       if (overload_debug)
 	{
 	  if (fns_ptr != NULL)
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded method instance %s, # of parms %d\n",
-			      fns_ptr[ix].physname, nparms);
+			      fns_ptr[ix].physname, (int) parm_types.size ());
 	  else if (xm_worker_vec != NULL)
 	    fprintf_filtered (gdb_stderr,
 			      "Xmethod worker, # of parms %d\n",
-			      nparms);
+			      (int) parm_types.size ());
 	  else
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded function instance "
 			      "%s # of parms %d\n",
 			      SYMBOL_DEMANGLED_NAME (oload_syms[ix]), 
-			      nparms);
-	  for (jj = 0; jj < nargs - static_offset; jj++)
+			      (int) parm_types.size ());
+	  for (jj = 0; jj < args.size () - static_offset; jj++)
 	    fprintf_filtered (gdb_stderr,
 			      "...Badness @ %d : %d\n", 
 			      jj, bv->rank[jj].rank);
diff --git a/gdb/value.c b/gdb/value.c
index 38fc18e0f6..c7b8468b39 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2583,24 +2583,23 @@ value_from_xmethod (xmethod_worker_up &&worker)
 /* Return the type of the result of TYPE_CODE_XMETHOD value METHOD.  */
 
 struct type *
-result_type_of_xmethod (struct value *method, int argc, struct value **argv)
+result_type_of_xmethod (struct value *method, gdb::array_view<value *> argv)
 {
   gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
-	      && method->lval == lval_xcallable && argc > 0);
+	      && method->lval == lval_xcallable && !argv.empty ());
 
-  return method->location.xm_worker->get_result_type
-    (argv[0], argv + 1, argc - 1);
+  return method->location.xm_worker->get_result_type (argv[0], argv.slice (1));
 }
 
 /* Call the xmethod corresponding to the TYPE_CODE_XMETHOD value METHOD.  */
 
 struct value *
-call_xmethod (struct value *method, int argc, struct value **argv)
+call_xmethod (struct value *method, gdb::array_view<value *> argv)
 {
   gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
-	      && method->lval == lval_xcallable && argc > 0);
+	      && method->lval == lval_xcallable && !argv.empty ());
 
-  return method->location.xm_worker->invoke (argv[0], argv + 1, argc - 1);
+  return method->location.xm_worker->invoke (argv[0], argv.slice (1));
 }
 \f
 /* Extract a value as a C number (either long or double).
diff --git a/gdb/value.h b/gdb/value.h
index 4d75c966ed..54caa58e7f 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -835,7 +835,7 @@ extern struct value *value_static_field (struct type *type, int fieldno);
 
 enum oload_search_type { NON_METHOD, METHOD, BOTH };
 
-extern int find_overload_match (struct value **args, int nargs,
+extern int find_overload_match (gdb::array_view<value *> args,
 				const char *name,
 				enum oload_search_type method,
 				struct value **objp, struct symbol *fsym,
@@ -1175,10 +1175,10 @@ char *value_internal_function_name (struct value *);
 extern struct value *value_from_xmethod (xmethod_worker_up &&worker);
 
 extern struct type *result_type_of_xmethod (struct value *method,
-					    int argc, struct value **argv);
+					    gdb::array_view<value *> argv);
 
 extern struct value *call_xmethod (struct value *method,
-				   int argc, struct value **argv);
+				   gdb::array_view<value *> argv);
 
 /* Given a discriminated union type and some corresponding value
    contents, this will return the field index of the currently active
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/6] valops.c: Some more gdb::array_view
  2018-10-17 18:03   ` Simon Marchi
@ 2018-11-21 12:48     ` Pedro Alves
  0 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2018-11-21 12:48 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 10/17/2018 07:03 PM, Simon Marchi wrote:
> On 2018-10-15 11:11 a.m., Pedro Alves wrote:
>> This commit replaces some more use of pointer+length pairs in the
>> overload resolution code with gdb::array_view.
>>
>> find_oload_champ's interface is simplified/normalized: the xmethods
>> parameter is converted from std::vector to array pointer, and then the
>> num_fns parameter is always passed in, no matter the array which is
>> non-NULL.  I tweaked the formatting of callers a little bit here and
>> there so that the 3 optional parameters are all in the same line.  (I
>> tried making the 3 optional array parameters be array_views, but the
>> resulting code didn't look as nice.)
> 
> I don't really understand what's happening in that code, but it looks to me
> like the behavior is kept, which is good.

You can look at find_oload_champ as a template function -- it finds
the best overload match from a given set of functions.  Now, I'm
calling it a "template", because there are 3 different sources of
functions to consider: free functions, class methods, or xmethods, and
each of those are arrays/vectors of different types.  Only one of those
sources can be passed down to the function.  The non-normalized thing with
the function currently is that two of the sources are passed as "pointer
to array", while one source (xmethods) is passed as an std::vector.
When you pass down one of the "pointer to array" sources (functions
or class methods), you need to pass the array length as well in 
NUM_FDS.  But when you pass down xmethods, you don't pass down the
vector's length, because the function gets it from the vector itself.
The patch essentially makes the xmethod source case be passed by
"pointer to array" as well, so that all sources are implemented
the same way.  And in turns means that we now pass down the array
length via NUM_FDS for xmethods too.

> 
>> @@ -2572,23 +2564,28 @@ find_overload_match (gdb::array_view<value *> args,
>>        /* If we are dealing with stub method types, they should have
>>  	 been resolved by find_method_list via
>>  	 value_find_oload_method_list above.  */
>> -      if (fns_ptr)
>> +      if (!fns_list.empty ())
>>  	{
>> -	  gdb_assert (TYPE_SELF_TYPE (fns_ptr[0].type) != NULL);
>> +	  gdb_assert (TYPE_SELF_TYPE (fns_list[0].type) != NULL);
>>  
>> -	  src_method_oload_champ = find_oload_champ (args,
>> -						     num_fns, fns_ptr, NULL,
>> -						     NULL, &src_method_badness);
>> +	  src_method_oload_champ
>> +	    = find_oload_champ (args,
>> +				fns_list.size (),
>> +				fns_list.data (), NULL, NULL,
>> +				&src_method_badness);
>>  
>>  	  src_method_match_quality = classify_oload_match
>>  	    (src_method_badness, args.size (),
>> -	     oload_method_static_p (fns_ptr, src_method_oload_champ));
>> +	     oload_method_static_p (fns_list.data (), src_method_oload_champ));
>>  	}
>>  
>>        if (!xm_worker_vec.empty ())
>>  	{
>> -	  ext_method_oload_champ = find_oload_champ (args, 0, NULL, &xm_worker_vec,
>> -						     NULL, &ext_method_badness);
>> +	  ext_method_oload_champ
>> +	    = find_oload_champ (args,
>> +				xm_worker_vec.size (),
>> +				NULL, xm_worker_vec.data (), NULL,
>> +				&ext_method_badness);
> 
> The previous code passed a size of 0... was it an error?

Nope.  See above.

> 
>> @@ -2984,20 +2982,20 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
>>     or XM_WORKER_VEC, respectively.  One, and only one of FNS_PTR,
>>     OLOAD_SYMS and XM_WORKER_VEC can be non-NULL.
>>  
>> -   If XM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
>> -   or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
>> +   NUM_FNS is the length of the array pointed at by FNS_PTR,
>> +   OLOAD_SYMS of XM_WORKER_VEC, whichever is non-NULL.
> 
> of -> or

Fixed, thanks.

Here's what I merged.  I merged patch 6/6 as well.

From 85cca2bcbc7833b33d4b61d7b7e0e75b9afa063b Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 21 Nov 2018 11:55:14 +0000
Subject: [PATCH 5/6] valops.c: Some more gdb::array_view

This commit replaces some more use of pointer+length pairs in the
overload resolution code with gdb::array_view.

find_oload_champ's interface is simplified/normalized: the xmethods
parameter is converted from std::vector to array pointer, and then the
num_fns parameter is always passed in, no matter the array which is
non-NULL.  I tweaked the formatting of callers a little bit here and
there so that the 3 optional parameters are all in the same line.  (I
tried making the 3 optional array parameters be array_views, but the
resulting code didn't look as nice.)

gdb/ChangeLog:
2018-11-21  Pedro Alves  <palves@redhat.com>

	* valops.c (find_method_list): Replace pointer and length
	parameters with an gdb::array_view.  Adjust.
	(value_find_oload_method_list): Likewise.
	(find_overload_match): Use gdb::array_view for methods list.
	Adjust to find_oload_champ interface change.
	(find_oload_champ): 'xm_worker_vec' parameter now a pointer/array.
	'num_fns' parameter now a size_t.  Eliminate 'fn_count' local.
---
 gdb/ChangeLog |  10 ++++++
 gdb/valops.c  | 101 +++++++++++++++++++++++++++-------------------------------
 2 files changed, 57 insertions(+), 54 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5ae9ae7b1b..ff9eed7dee 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,13 @@
+2018-11-21  Pedro Alves  <palves@redhat.com>
+
+	* valops.c (find_method_list): Replace pointer and length
+	parameters with an gdb::array_view.  Adjust.
+	(value_find_oload_method_list): Likewise.
+	(find_overload_match): Use gdb::array_view for methods list.
+	Adjust to find_oload_champ interface change.
+	(find_oload_champ): 'xm_worker_vec' parameter now a pointer/array.
+	'num_fns' parameter now a size_t.  Eliminate 'fn_count' local.
+
 2018-11-21  Pedro Alves  <palves@redhat.com>
 
 	* gdbtypes.c (compare_badness): Change type of parameters to const
diff --git a/gdb/valops.c b/gdb/valops.c
index 1b4a8e123c..1d68c04bfe 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -66,10 +66,12 @@ static int find_oload_champ_namespace_loop (gdb::array_view<value *> args,
 					    badness_vector *, int *,
 					    const int no_adl);
 
-static int find_oload_champ (gdb::array_view<value *> args, int,
-			     struct fn_field *,
-			     const std::vector<xmethod_worker_up> *,
-			     struct symbol **, badness_vector *);
+static int find_oload_champ (gdb::array_view<value *> args,
+			     size_t num_fns,
+			     fn_field *fns_ptr,
+			     xmethod_worker_up *xm_worker_vec,
+			     symbol **oload_syms,
+			     badness_vector *oload_champ_bv);
 
 static int oload_method_static_p (struct fn_field *, int);
 
@@ -95,11 +97,6 @@ static CORE_ADDR allocate_space_in_inferior (int);
 
 static struct value *cast_into_complex (struct type *, struct value *);
 
-static void find_method_list (struct value **, const char *,
-			      LONGEST, struct type *, struct fn_field **, int *,
-			      std::vector<xmethod_worker_up> *,
-			      struct type **, LONGEST *);
-
 int overload_resolution = 0;
 static void
 show_overload_resolution (struct ui_file *file, int from_tty,
@@ -2292,7 +2289,7 @@ value_union_variant (struct type *union_type, const gdb_byte *contents)
 }
 
 /* Search through the methods of an object (and its bases) to find a
-   specified method.  Return the pointer to the fn_field list FN_LIST of
+   specified method.  Return a reference to the fn_field list FN_LIST of
    overloaded instances defined in the source language.  If available
    and matching, a vector of matching xmethods defined in extension
    languages are also returned in XM_WORKER_VEC
@@ -2316,7 +2313,7 @@ value_union_variant (struct type *union_type, const gdb_byte *contents)
 static void
 find_method_list (struct value **argp, const char *method,
 		  LONGEST offset, struct type *type,
-		  struct fn_field **fn_list, int *num_fns,
+		  gdb::array_view<fn_field> *fn_list,
 		  std::vector<xmethod_worker_up> *xm_worker_vec,
 		  struct type **basetype, LONGEST *boffset)
 {
@@ -2330,7 +2327,7 @@ find_method_list (struct value **argp, const char *method,
      This function is called recursively to search through base classes.
      If there is a source method match found at some stage, then we need not
      look for source methods in consequent recursive calls.  */
-  if ((*fn_list) == NULL)
+  if (fn_list->empty ())
     {
       for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
 	{
@@ -2341,9 +2338,8 @@ find_method_list (struct value **argp, const char *method,
 	    {
 	      int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
 	      f = TYPE_FN_FIELDLIST1 (type, i);
-	      *fn_list = f;
+	      *fn_list = gdb::make_array_view (f, len);
 
-	      *num_fns = len;
 	      *basetype = type;
 	      *boffset = offset;
 
@@ -2385,7 +2381,7 @@ find_method_list (struct value **argp, const char *method,
 	}
 
       find_method_list (argp, method, base_offset + offset,
-			TYPE_BASECLASS (type, i), fn_list, num_fns,
+			TYPE_BASECLASS (type, i), fn_list,
 			xm_worker_vec, basetype, boffset);
     }
 }
@@ -2398,9 +2394,8 @@ find_method_list (struct value **argp, const char *method,
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is the method name.
    OFFSET is the offset within the value contents.
-   FN_LIST is the pointer to matching overloaded instances defined in
+   FN_LIST is the list of matching overloaded instances defined in
       source language.
-   NUM_FNS is the number of overloaded instances.
    XM_WORKER_VEC is the vector of matching xmethod workers defined in
       extension languages.
    BASETYPE is set to the type of the base subobject that defines the
@@ -2409,8 +2404,8 @@ find_method_list (struct value **argp, const char *method,
 
 static void
 value_find_oload_method_list (struct value **argp, const char *method,
-                              LONGEST offset, struct fn_field **fn_list,
-                              int *num_fns,
+			      LONGEST offset,
+			      gdb::array_view<fn_field> *fn_list,
 			      std::vector<xmethod_worker_up> *xm_worker_vec,
 			      struct type **basetype, LONGEST *boffset)
 {
@@ -2436,11 +2431,10 @@ value_find_oload_method_list (struct value **argp, const char *method,
   gdb_assert (fn_list != NULL && xm_worker_vec != NULL);
 
   /* Clear the lists.  */
-  *fn_list = NULL;
-  *num_fns = 0;
+  *fn_list = {};
   xm_worker_vec->clear ();
 
-  find_method_list (argp, method, 0, t, fn_list, num_fns, xm_worker_vec,
+  find_method_list (argp, method, 0, t, fn_list, xm_worker_vec,
 		    basetype, boffset);
 }
 
@@ -2514,13 +2508,11 @@ find_overload_match (gdb::array_view<value *> args,
 
   struct value *temp = obj;
   /* For methods, the list of overloaded methods.  */
-  struct fn_field *fns_ptr = NULL;
+  gdb::array_view<fn_field> fns_list;
   /* For non-methods, the list of overloaded function symbols.  */
   std::vector<symbol *> oload_syms;
   /* For xmethods, the vector of xmethod workers.  */
   std::vector<xmethod_worker_up> xm_worker_vec;
-  /* Number of overloaded instances being considered.  */
-  int num_fns = 0;
   struct type *basetype = NULL;
   LONGEST boffset;
 
@@ -2560,11 +2552,11 @@ find_overload_match (gdb::array_view<value *> args,
 	}
 
       /* Retrieve the list of methods with the name NAME.  */
-      value_find_oload_method_list (&temp, name, 0, &fns_ptr, &num_fns,
+      value_find_oload_method_list (&temp, name, 0, &fns_list,
 				    &xm_worker_vec, &basetype, &boffset);
       /* If this is a method only search, and no methods were found
          the search has failed.  */
-      if (method == METHOD && (!fns_ptr || !num_fns) && xm_worker_vec.empty ())
+      if (method == METHOD && fns_list.empty () && xm_worker_vec.empty ())
 	error (_("Couldn't find method %s%s%s"),
 	       obj_type_name,
 	       (obj_type_name && *obj_type_name) ? "::" : "",
@@ -2572,23 +2564,28 @@ find_overload_match (gdb::array_view<value *> args,
       /* If we are dealing with stub method types, they should have
 	 been resolved by find_method_list via
 	 value_find_oload_method_list above.  */
-      if (fns_ptr)
+      if (!fns_list.empty ())
 	{
-	  gdb_assert (TYPE_SELF_TYPE (fns_ptr[0].type) != NULL);
+	  gdb_assert (TYPE_SELF_TYPE (fns_list[0].type) != NULL);
 
-	  src_method_oload_champ = find_oload_champ (args,
-						     num_fns, fns_ptr, NULL,
-						     NULL, &src_method_badness);
+	  src_method_oload_champ
+	    = find_oload_champ (args,
+				fns_list.size (),
+				fns_list.data (), NULL, NULL,
+				&src_method_badness);
 
 	  src_method_match_quality = classify_oload_match
 	    (src_method_badness, args.size (),
-	     oload_method_static_p (fns_ptr, src_method_oload_champ));
+	     oload_method_static_p (fns_list.data (), src_method_oload_champ));
 	}
 
       if (!xm_worker_vec.empty ())
 	{
-	  ext_method_oload_champ = find_oload_champ (args, 0, NULL, &xm_worker_vec,
-						     NULL, &ext_method_badness);
+	  ext_method_oload_champ
+	    = find_oload_champ (args,
+				xm_worker_vec.size (),
+				NULL, xm_worker_vec.data (), NULL,
+				&ext_method_badness);
 	  ext_method_match_quality = classify_oload_match (ext_method_badness,
 							   args.size (), 0);
 	}
@@ -2787,22 +2784,22 @@ find_overload_match (gdb::array_view<value *> args,
     }
 
   if (staticp != NULL)
-    *staticp = oload_method_static_p (fns_ptr, method_oload_champ);
+    *staticp = oload_method_static_p (fns_list.data (), method_oload_champ);
 
   if (method_oload_champ >= 0)
     {
       if (src_method_oload_champ >= 0)
 	{
-	  if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ)
+	  if (TYPE_FN_FIELD_VIRTUAL_P (fns_list, method_oload_champ)
 	      && noside != EVAL_AVOID_SIDE_EFFECTS)
 	    {
-	      *valp = value_virtual_fn_field (&temp, fns_ptr,
+	      *valp = value_virtual_fn_field (&temp, fns_list.data (),
 					      method_oload_champ, basetype,
 					      boffset);
 	    }
 	  else
-	    *valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
-				    basetype, boffset);
+	    *valp = value_fn_field (&temp, fns_list.data (),
+				    method_oload_champ, basetype, boffset);
 	}
       else
 	*valp = value_from_xmethod
@@ -2942,7 +2939,8 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
     }
 
   badness_vector new_oload_champ_bv;
-  new_oload_champ = find_oload_champ (args, new_oload_syms.size (),
+  new_oload_champ = find_oload_champ (args,
+				      new_oload_syms.size (),
 				      NULL, NULL, new_oload_syms.data (),
 				      &new_oload_champ_bv);
 
@@ -2979,20 +2977,20 @@ find_oload_champ_namespace_loop (gdb::array_view<value *> args,
    or XM_WORKER_VEC, respectively.  One, and only one of FNS_PTR,
    OLOAD_SYMS and XM_WORKER_VEC can be non-NULL.
 
-   If XM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
-   or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
+   NUM_FNS is the length of the array pointed at by FNS_PTR,
+   OLOAD_SYMS or XM_WORKER_VEC, whichever is non-NULL.
 
    Return the index of the best match; store an indication of the
    quality of the match in OLOAD_CHAMP_BV.  */
 
 static int
 find_oload_champ (gdb::array_view<value *> args,
-		  int num_fns, struct fn_field *fns_ptr,
-		  const std::vector<xmethod_worker_up> *xm_worker_vec,
-		  struct symbol **oload_syms,
+		  size_t num_fns,
+		  fn_field *fns_ptr,
+		  xmethod_worker_up *xm_worker_vec,
+		  symbol **oload_syms,
 		  badness_vector *oload_champ_bv)
 {
-  int ix;
   /* A measure of how good an overloaded instance is.  */
   badness_vector bv;
   /* Index of best overloaded function.  */
@@ -3007,20 +3005,15 @@ find_oload_champ (gdb::array_view<value *> args,
   gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) + (xm_worker_vec != NULL)
 	      == 1);
 
-  int fn_count = xm_worker_vec != NULL ? xm_worker_vec->size () : num_fns;
-
   /* Consider each candidate in turn.  */
-  for (ix = 0; ix < fn_count; ix++)
+  for (size_t ix = 0; ix < num_fns; ix++)
     {
       int jj;
       int static_offset = 0;
       std::vector<type *> parm_types;
 
       if (xm_worker_vec != NULL)
-	{
-	  xmethod_worker *worker = (*xm_worker_vec)[ix].get ();
-	  parm_types = worker->get_arg_types ();
-	}
+	parm_types = xm_worker_vec[ix]->get_arg_types ();
       else
 	{
 	  size_t nparms;
-- 
2.14.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/6] invoke_xmethod & array_view
  2018-11-21 12:47     ` Pedro Alves
@ 2018-11-26 17:18       ` Simon Marchi
  2018-11-26 17:54         ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2018-11-26 17:18 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Simon Marchi, gdb-patches

On 2018-11-21 07:46, Pedro Alves wrote:
> I changed it, though I'm not a big fan of that rule.
> 
> As I wrote at <https://gcc.gnu.org/ml/gcc/2018-07/msg00190.html>, I 
> used to
> prefer avoiding non-const reference output parameters too back in my
> earlier C++ days, but I no longer do so much nowadays.
> 
> The main point of avoiding non-const reference parameters is that
> supposedly they make function callers unclearer, with no
> visual indication that the function modified the argument.  The
> idea is that "&foo" instead of "foo" is that visual distinction.
> But, that point can easily become moot because the visual distinction
> can be easily lost with pointers too:
> 
>  // the usual argument is that using pointers for output parameters 
> shows
>  // clearly that bar is going to be modified:
>  function (foo, &bar);
> 
>  // but well, we often works with pointers, and if "bar" is a pointer,
>  // we don't get any visual clue anyway either:
>  function (foo, bar);
> 
>  // which suggests that what really helps is seeing the output
>  // variable nearby, suggesting to define it right before the
>  // function call that fills it in, and I would go as far
>  // as saying that clearer symbol names help even more.  For e.g.:
>  B bar_out;
>  fill_bar (foo, bar_out);

Well, I think that doing both (passing a pointer to the function, and 
defining the variable as close as possible) helps, they are not mutually 
exclusive.  As for the name, it depends on the situation...  if you are 
then going to pass bar_out as input to another function, then it's 
misleading.

I think what helps the most is the fact that arguments passed by 
non-const references are highlighted red in my IDE :)

> I think that symbol and function naming above is much more important
> than "&bar" vs "bar".  A function called "fill_bar" is clearly going
> to write to its "bar_out" argument.

As mentioned above, an "out" argument passed to a function call may be 
an "in" argument to the next one.  I agree that good naming is 
important, but there is no one trick that will make the code "100%" 
readable.  They all help a little bit towards that goal.

> Also, a pointer can be null, while a reference can not.  So
> a reference parameter automatically implies that you can't pass
> a NULL pointer to the function (which makes the function's
> implementation a little bit clearer too), while with a pointer 
> parameter
> you have to document that, and maybe assert it. With a reference, the
> compiler is free to optimize accordingly (assume non-null), while with
> a pointer, you have to use gcc's attribute nonnull if you want that,
> which no one does.
> 
> Also, for std::vector parameters in particular, passing by pointer
> leads to uglier code in the function's implementation, like e.g.,
> 
>  (*vec)[idx] = 0;
> 
> instead of:
> 
>  vec[idx] = 0;
> 
> We end up with a few instances like that in the series, though 
> admittedly
> not that many, otherwise I think I'd add something like:
> 
>   auto &vec = *vec_param;
> 
> at the top of the function and then use vec throughout.

I acknowledge all these downsides.  My opinion (as of today) is that 
they are reasonable trade-offs.  I'm in the camp of "code is written 
once, read many times".  I think that when writing it, it's not 
difficult to look up what the function you are calling expects (can a 
pointer be null).  But when reading a function, if the little & sign can 
save a round trip to the called function's doc, I think it's worth it.

> So in sum, I nowadays tend to look at reference vs parameter more from
> the "pointer: optional, can be NULL", vs "reference: non-optional" 
> angle.
> Though, given GDB's history, we definetely use pointers pervasively
> in function parameters even when they're not supposed to be optional,
> that's for sure.

For "in" parameters, I think it's a no-brainer to do that.

> Maybe we could come up with some middle ground rule, like always
> putting in-out and output parameters last, and stressing to use
> clear symbol names.

Hmmm maybe, I would have to see it in practice to judge how feasible it 
is.

> Anyway, I don't want to block on that discussion (my 1 month round trip
> time not helping! :-D), so I did the change.

Thanks!  Note that I have introduced this rule kind of unilaterally 
after having no response when I proposed it:

https://sourceware.org/ml/gdb-patches/2018-03/msg00145.html
https://sourceware.org/ml/gdb-patches/2018-05/msg00450.html

I thought it was reasonable to do so because it's not a huge commitment 
and easily reversible if people ended up disagreeing.  So it's not as if 
it's set in stone.

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/6] invoke_xmethod & array_view
  2018-11-26 17:18       ` Simon Marchi
@ 2018-11-26 17:54         ` Pedro Alves
  2018-11-26 18:28           ` Simon Marchi
  0 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2018-11-26 17:54 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Simon Marchi, gdb-patches

On 11/26/2018 05:18 PM, Simon Marchi wrote:

> I acknowledge all these downsides.  My opinion (as of today) is that they are reasonable trade-offs.  I'm in the camp of "code is written once, read many times".  I think that when writing it, it's not difficult to look up what the function you are calling expects (can a pointer be null).  But when reading a function, if the little & sign can save a round trip to the called function's doc, I think it's worth it.

In the patch series in question, do you think it helps?  IMHO it
doesn't.  Passing a vector by copy would be so strange that I'd
never think that that is what is going on.  Which leaves non
or non-const references.  And then if one has to look up
the function description to know the function is adding to the vector,
then that means that one doesn't really have a clue what the function
is doing, IMO.  Once you know, then you just know and the & doesn't
really help.

John's series is also passing output vectors by non-const reference:

 https://sourceware.org/ml/gdb-patches/2018-11/msg00171.html

and that code looks pretty clear to me as is.

Maybe it's particular to vectors/containers, not sure.  Maybe
a prototype like:
  void foo (int i, int &bar, float f, S *);
would be more confusing to me.  Can't say either, I guess because
I'm not seeing myself writing a function with such a prototype.

> 
>> So in sum, I nowadays tend to look at reference vs parameter more from
>> the "pointer: optional, can be NULL", vs "reference: non-optional" angle.
>> Though, given GDB's history, we definetely use pointers pervasively
>> in function parameters even when they're not supposed to be optional,
>> that's for sure.
> 
> For "in" parameters, I think it's a no-brainer to do that.
> 
>> Maybe we could come up with some middle ground rule, like always
>> putting in-out and output parameters last, and stressing to use
>> clear symbol names.
> 
> Hmmm maybe, I would have to see it in practice to judge how feasible it is.
>> Anyway, I don't want to block on that discussion (my 1 month round trip
>> time not helping! :-D), so I did the change.
> 
> Thanks!  Note that I have introduced this rule kind of unilaterally after having no response when I proposed it:
> 
> https://sourceware.org/ml/gdb-patches/2018-03/msg00145.html
> https://sourceware.org/ml/gdb-patches/2018-05/msg00450.html
> 
> I thought it was reasonable to do so because it's not a huge commitment and easily reversible if people ended up disagreeing.  So it's not as if it's set in stone.
Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/6] invoke_xmethod & array_view
  2018-11-26 17:54         ` Pedro Alves
@ 2018-11-26 18:28           ` Simon Marchi
  0 siblings, 0 replies; 20+ messages in thread
From: Simon Marchi @ 2018-11-26 18:28 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Simon Marchi, gdb-patches

On 2018-11-26 12:54, Pedro Alves wrote:
> On 11/26/2018 05:18 PM, Simon Marchi wrote:
> 
>> I acknowledge all these downsides.  My opinion (as of today) is that 
>> they are reasonable trade-offs.  I'm in the camp of "code is written 
>> once, read many times".  I think that when writing it, it's not 
>> difficult to look up what the function you are calling expects (can a 
>> pointer be null).  But when reading a function, if the little & sign 
>> can save a round trip to the called function's doc, I think it's worth 
>> it.
> 
> In the patch series in question, do you think it helps?  IMHO it
> doesn't.  Passing a vector by copy would be so strange that I'd
> never think that that is what is going on.  Which leaves non
> or non-const references.  And then if one has to look up
> the function description to know the function is adding to the vector,
> then that means that one doesn't really have a clue what the function
> is doing, IMO.  Once you know, then you just know and the & doesn't
> really help.

It's hard to tell now because as you say, once I know, I know.  And I 
happen to know now :).  Also, this is a case of

    did_it_work = get_stuff (stuff);

So in this case, I admit it would be clear either way.

> 
> John's series is also passing output vectors by non-const reference:
> 
>  https://sourceware.org/ml/gdb-patches/2018-11/msg00171.html
> 
> and that code looks pretty clear to me as is.

There, it kinda helps that the variable is named "result":

   get_syscalls_by_group (gdbarch, group_name, result)

If the result of get_syscalls_by_groups was used for something else than 
being returned, it probably wouldn't have been named "result".  But even 
with that name, I think the & adds a little something that makes it 
obvious at the first eyesight, even before parsing the text:

   get_syscalls_by_group (gdbarch, group_name, &result)

I'm not saying that it's a major impediment to reading the code, just 
one little thing that contribute to readability (IMO).  Again, if people 
believe this rule is more an annoyance than anything else, we can just 
remove it.

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2018-11-26 18:28 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-15 15:11 [PATCH 0/6] Use gdb::array_view some more, plug leaks Pedro Alves
2018-10-15 15:11 ` [PATCH 5/6] valops.c: Some more gdb::array_view Pedro Alves
2018-10-17 18:03   ` Simon Marchi
2018-11-21 12:48     ` Pedro Alves
2018-10-15 15:11 ` [PATCH 3/6] Eliminate make_symbol_overload_list-related globals & cleanup Pedro Alves
2018-10-17 17:25   ` Simon Marchi
2018-11-21 12:47     ` Pedro Alves
2018-10-15 15:11 ` [PATCH 1/6] Use gdb:array_view in call_function_by_hand & friends Pedro Alves
2018-10-17  1:45   ` Simon Marchi
2018-11-21 12:39     ` Pedro Alves
2018-10-15 15:11 ` [PATCH 2/6] invoke_xmethod & array_view Pedro Alves
2018-10-17 16:21   ` Simon Marchi
2018-11-21 12:47     ` Pedro Alves
2018-11-26 17:18       ` Simon Marchi
2018-11-26 17:54         ` Pedro Alves
2018-11-26 18:28           ` Simon Marchi
2018-10-15 15:16 ` [PATCH 4/6] C++ify badness_vector, fix leaks Pedro Alves
2018-10-17 17:44   ` Simon Marchi
2018-11-21 12:47     ` Pedro Alves
2018-10-15 15:18 ` [PATCH 6/6] valops.c: Overload resolution code: Rename parameters/locals Pedro Alves

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).