[RFA,3/5] Use std::string, std::vector in rust-lang.c

Message ID 1474566656-15389-4-git-send-email-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey Sept. 22, 2016, 5:50 p.m. UTC
  This patche changes some spots in rust-lang.c to use std::string or
std::vector, removing some cleanups.

2016-09-22  Tom Tromey  <tom@tromey.com>

	* rust-lang.c: Include <string> and <vector>.
	(rust_evaluate_funcall): Use std::vector, std::string.
	(rust_evaluate_subexp): Use std::string.
	(rust_lookup_symbol_nonlocal): Use std::string.
---
 gdb/ChangeLog   |  7 +++++++
 gdb/rust-lang.c | 38 ++++++++++++++++----------------------
 2 files changed, 23 insertions(+), 22 deletions(-)
  

Comments

Pedro Alves Sept. 22, 2016, 7:02 p.m. UTC | #1
On 09/22/2016 06:50 PM, Tom Tromey wrote:
>    int num_args = exp->elts[*pos + 1].longconst;
>    const char *method;
> -  char *name;
> +  std::string name;

While we required declaring variables at the top of the
scope in C, in C++ it no longer makes sense.  Particularly
if the variable's type as a constructor.

So I think we should move the variable declaration to the
initialization line, to avoid default constructing the variable
and then resetting it afterwards, as the compiler may
not be smart enough to elide that.

>  
> -  name = concat (TYPE_TAG_NAME (type), "::", method, (char *) NULL);
> -  make_cleanup (xfree, name);
> +  name = std::string (TYPE_TAG_NAME (type)) + "::" + method;
>  


> -	  char *scopedname = concat (scope, "::", name, (char *) NULL);
> -	  struct cleanup *cleanup = make_cleanup (xfree, scopedname);
> +	  std::string scopedname;
> +
> +	  scopedname = std::string (scope) + "::" + name;

Here too.  Throughout the series, really.

Thanks,
Pedro Alves
  
Tom Tromey Sept. 22, 2016, 7:15 p.m. UTC | #2
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> So I think we should move the variable declaration to the
Pedro> initialization line, to avoid default constructing the variable
Pedro> and then resetting it afterwards, as the compiler may
Pedro> not be smart enough to elide that.

I think so too -- I had avoided this on account of earlier objections to
this style.

Tom
  
Pedro Alves Sept. 22, 2016, 7:24 p.m. UTC | #3
On 09/22/2016 08:15 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
> 
> Pedro> So I think we should move the variable declaration to the
> Pedro> initialization line, to avoid default constructing the variable
> Pedro> and then resetting it afterwards, as the compiler may
> Pedro> not be smart enough to elide that.
> 
> I think so too -- I had avoided this on account of earlier objections to
> this style.

In C, it'd require C99, while we were C89.  Other than that,
it was just a coding convention.  

But we now have technical reasons for not putting variables
at top of the scope.  There's the efficiency reason, and then
some types may not even have a default constructor, and the
arguments that'd need to be passed to the constructor
might not have been computed at the top of the scope, making
it impossible to declare the variable at the top, unless we'd
open an ugly new scope...

So I think there's no ground for objection.

Thanks,
Pedro Alves
  
Pierre Muller Sept. 22, 2016, 7:35 p.m. UTC | #4
> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : jeudi 22 septembre 2016 21:25
> À : Tom Tromey
> Cc : gdb-patches@sourceware.org
> Objet : Re: [RFA 3/5] Use std::string, std::vector in rust-lang.c
> 
> On 09/22/2016 08:15 PM, Tom Tromey wrote:
> >>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
> >
> > Pedro> So I think we should move the variable declaration to the
> > Pedro> initialization line, to avoid default constructing the
> variable
> > Pedro> and then resetting it afterwards, as the compiler may
> > Pedro> not be smart enough to elide that.
> >
> > I think so too -- I had avoided this on account of earlier objections
> to
> > this style.
> 
> In C, it'd require C99, while we were C89.  Other than that,
> it was just a coding convention.
> 
> But we now have technical reasons for not putting variables
> at top of the scope.  There's the efficiency reason, and then
> some types may not even have a default constructor, and the
> arguments that'd need to be passed to the constructor
> might not have been computed at the top of the scope, making
> it impossible to declare the variable at the top, unless we'd
> open an ugly new scope...

  Just out of curiosity:
how are such variables treated by gcc regarding debug information?

  What is the scope of definition of those variables?
And is it correctly handled by current GDB?

  IIRC (but my knowledge about C++ if far
worse than for plain C.. which itself I only learned to be able to
contribute to GDB...) the reason why we can remove the cleanups is
that the compiler will insert auto--magically
the destructors of those local variables at the end of
their respective scope, is this correct? 
 
> So I think there's no ground for objection.

  Not that I want to raise an objection,
I just wonder if debugging GDB by itself will remain as easy as it was!

Pierre Muller
pascal language support maintainer...
  
Pedro Alves Sept. 22, 2016, 11:10 p.m. UTC | #5
On 09/22/2016 08:35 PM, Pierre Muller wrote:

>   Just out of curiosity:
> how are such variables treated by gcc regarding debug information?
> 
>   What is the scope of definition of those variables?
> And is it correctly handled by current GDB?

On my system, they look like as if declared at the top of
the scope.  Up until they're initialized, they'll have garbage
contents, and that's what gdb will show.  But that's no different from
actually declaring a variable at the top of the scope and only
initializing it after.  It's not a big deal.

There's a GNU extension that I think is meant to make it possible
for the debugger to treat uninitialized variables
specially (DW_OP_GNU_uninit), though I don't think we do
much with it.  Not sure gcc emits it, even.

> 
>   IIRC (but my knowledge about C++ if far
> worse than for plain C.. which itself I only learned to be able to
> contribute to GDB...) the reason why we can remove the cleanups is
> that the compiler will insert auto--magically
> the destructors of those local variables at the end of
> their respective scope, is this correct? 

Correct.

>  
>> So I think there's no ground for objection.
> 
>   Not that I want to raise an objection,
> I just wonder if debugging GDB by itself will remain as easy as it was!

Hope so too...

Thanks,
Pedro Alves
  
Tom Tromey Sept. 23, 2016, 3:49 p.m. UTC | #6
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> There's a GNU extension that I think is meant to make it possible
Pedro> for the debugger to treat uninitialized variables
Pedro> specially (DW_OP_GNU_uninit), though I don't think we do
Pedro> much with it.

There were never any docs for it :(
I think it probably should have been a piece-terminating operation but
it was never clear if this was how it was actually supposed to work.
I stuck a comment in dwarf_expr_require_composition to this effect back
in the day.

Pedro> Not sure gcc emits it, even.

It does, but I don't know under what conditions.
There's code in dwarf2out.c like:

  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));

I don't know when that happens though.

Perhaps this could be cleaned up a bit, say by making DW_OP_GNU_uninit a
piece terminator (I forget the official term here) and by changing gcc
to emit a location list that indicates that the object is uninitialized
until after the constructor is run.  It might be a little friendlier to
users, dunno.

Tom
  
Pedro Alves Sept. 23, 2016, 4:14 p.m. UTC | #7
On 09/23/2016 04:49 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
> 
> Pedro> There's a GNU extension that I think is meant to make it possible
> Pedro> for the debugger to treat uninitialized variables
> Pedro> specially (DW_OP_GNU_uninit), though I don't think we do
> Pedro> much with it.
> 
> There were never any docs for it :(

I think all there is the original gcc and gdb patches:

  https://gcc.gnu.org/ml/gcc-patches/2007-05/msg00068.html

I remember seeing these back then, but I was still a gdb noob then.
I don't recall the history of the feature after that.  From a quick look,
it kind of looks like some pieces of the patches are in the respective
trees, but not all hunks.  Maybe they got in, and then mostly reverted.

Thanks,
Pedro Alves

> I think it probably should have been a piece-terminating operation but
> it was never clear if this was how it was actually supposed to work.
> I stuck a comment in dwarf_expr_require_composition to this effect back
> in the day.
> 
> Pedro> Not sure gcc emits it, even.
> 
> It does, but I don't know under what conditions.
> There's code in dwarf2out.c like:
> 
>   if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
>     add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
> 
> I don't know when that happens though.
> 
> Perhaps this could be cleaned up a bit, say by making DW_OP_GNU_uninit a
> piece terminator (I forget the official term here) and by changing gcc
> to emit a location list that indicates that the object is uninitialized
> until after the constructor is run.  It might be a little friendlier to
> users, dunno.
> 
> Tom
>
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2029bcb..670406d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,12 @@ 
 2016-09-22  Tom Tromey  <tom@tromey.com>
 
+	* rust-lang.c: Include <string> and <vector>.
+	(rust_evaluate_funcall): Use std::vector, std::string.
+	(rust_evaluate_subexp): Use std::string.
+	(rust_lookup_symbol_nonlocal): Use std::string.
+
+2016-09-22  Tom Tromey  <tom@tromey.com>
+
 	* cp-namespace.c: Include <string>.
 	(cp_search_static_and_baseclasses)
 	(cp_lookup_symbol_imports_or_template, find_symbol_in_baseclass):
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 77f7428..b9acfcf 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -32,6 +32,8 @@ 
 #include "rust-lang.h"
 #include "valprint.h"
 #include "varobj.h"
+#include <string>
+#include <vector>
 
 extern initialize_file_ftype _initialize_rust_language;
 
@@ -1154,10 +1156,9 @@  rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
   int i;
   int num_args = exp->elts[*pos + 1].longconst;
   const char *method;
-  char *name;
+  std::string name;
   struct value *function, *result, *arg0;
-  struct value **args;
-  struct cleanup *cleanup;
+  std::vector<struct value *> args (num_args + 1);
   struct type *type, *fn_type;
   const struct block *block;
   struct block_symbol sym;
@@ -1183,8 +1184,6 @@  rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
       return arg0;
     }
 
-  args = XNEWVEC (struct value *, num_args + 1);
-  cleanup = make_cleanup (xfree, args);
   args[0] = arg0;
 
   /* We don't yet implement real Deref semantics.  */
@@ -1200,17 +1199,16 @@  rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
   if (TYPE_TAG_NAME (type) == NULL)
     error (_("Method call on nameless type"));
 
-  name = concat (TYPE_TAG_NAME (type), "::", method, (char *) NULL);
-  make_cleanup (xfree, name);
+  name = std::string (TYPE_TAG_NAME (type)) + "::" + method;
 
   block = get_selected_block (0);
-  sym = lookup_symbol (name, block, VAR_DOMAIN, NULL);
+  sym = lookup_symbol (name.c_str (), block, VAR_DOMAIN, NULL);
   if (sym.symbol == NULL)
-    error (_("Could not find function named '%s'"), name);
+    error (_("Could not find function named '%s'"), name.c_str ());
 
   fn_type = SYMBOL_TYPE (sym.symbol);
   if (TYPE_NFIELDS (fn_type) == 0)
-    error (_("Function '%s' takes no arguments"), name);
+    error (_("Function '%s' takes no arguments"), name.c_str ());
 
   if (TYPE_CODE (TYPE_FIELD_TYPE (fn_type, 0)) == TYPE_CODE_PTR)
     args[0] = value_addr (args[0]);
@@ -1223,8 +1221,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, num_args + 1, args);
-  do_cleanups (cleanup);
+    result = call_function_by_hand (function, num_args + 1, args.data ());
   return result;
 }
 
@@ -1601,14 +1598,11 @@  rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 	  {
 	    CORE_ADDR addr;
 	    int i;
-	    struct value **eltvec = XNEWVEC (struct value *, copies);
-	    struct cleanup *cleanup = make_cleanup (xfree, eltvec);
+	    std::vector<struct value *> eltvec (copies);
 
 	    for (i = 0; i < copies; ++i)
 	      eltvec[i] = elt;
-	    result = value_array (0, copies - 1, eltvec);
-
-	    do_cleanups (cleanup);
+	    result = value_array (0, copies - 1, eltvec.data ());
 	  }
 	else
 	  {
@@ -2036,14 +2030,14 @@  rust_lookup_symbol_nonlocal (const struct language_defn *langdef,
 
       if (scope[0] != '\0')
 	{
-	  char *scopedname = concat (scope, "::", name, (char *) NULL);
-	  struct cleanup *cleanup = make_cleanup (xfree, scopedname);
+	  std::string scopedname;
+
+	  scopedname = std::string (scope) + "::" + name;
 
-	  result = lookup_symbol_in_static_block (scopedname, block,
+	  result = lookup_symbol_in_static_block (scopedname.c_str (), block,
 						  domain);
 	  if (result.symbol == NULL)
-	    result = lookup_global_symbol (scopedname, block, domain);
-	  do_cleanups (cleanup);
+	    result = lookup_global_symbol (scopedname.c_str (), block, domain);
 	}
     }
   return result;