[PATCH v6 1/2] gdb: add annotation in 'info locals' command for variables shadowing case

Guinevere Larsen blarsen@redhat.com
Tue Jan 16 15:40:40 GMT 2024


On 22/11/2023 09:13, Abdul Basit Ijaz wrote:
> From: "Ijaz, Abdul B" <abdul.b.ijaz@intel.com>
>
> For C/C++/Fortran/Ada languages GDB prints same name variable multiple
> times in case of variable shadowing and it is confusing for user to identify
> which variable belongs to the current scope.  So for such cases add location
> info to the innermost listed variables and for super block variables add
> "shadowed" annotation in the form of "<file.c:line, shadowed>".
>
> Suppose we have
>
> 1:int x = 42;
> 2:  {
> 3:    int x = 99;
> 4:    int y = 52;
> 5:    x = 99; /* break here */
> 6:  }
>
> Currently:
>
> (gdb) info locals
> x = 99
> x = 42
> y = 52
>
> After applying this patch, we obtain:
>
> (gdb) info locals
> x = 99  <file.c:3>
> y = 52
> x = 42  <file.c:1, shadowed>
>
> The patch adds the location annotations by keeping track of inner block
> and already printed variables to identify shadowing.  So, GDB now prints
> "<file.c:line, shadowed>" for shadowed super-block variables and
> "<file.c:line>" for innermost declarations of such variables only.
>
> The location annotations are printed for shadowed variables in case of
> C/C++/Fortran/Ada languages.  In Rust, it is possible to declare a
> variable with the same name many times.  So in this case, just the first
> instance of the variable is printed.  RUST language test "var_reuse.exp"
> fails with rustc compiler version >= 1.73 so XFAIL is added accordingly.
> ---

Changes look good to me, and looks like a good feature.

Reviewed-By: Guinevere Larsen <blarsen@redhat.com>

-- 
Cheers,
Guinevere Larsen
She/Her/Hers

>   gdb/doc/gdb.texinfo                           | 15 ++++
>   gdb/printcmd.c                                | 11 ++-
>   gdb/stack.c                                   | 64 +++++++++++--
>   gdb/stack.h                                   |  3 +-
>   gdb/testsuite/gdb.ada/var_shadowing.exp       | 38 ++++++++
>   .../gdb.ada/var_shadowing/var_shadowing.adb   | 30 +++++++
>   gdb/testsuite/gdb.base/var-shadowing.c        | 49 ++++++++++
>   gdb/testsuite/gdb.base/var-shadowing.exp      | 90 +++++++++++++++++++
>   gdb/testsuite/gdb.base/var-shadowing2.c       | 16 ++++
>   gdb/testsuite/gdb.rust/var_reuse.exp          | 34 +++++++
>   gdb/testsuite/gdb.rust/var_reuse.rs           | 20 +++++
>   gdb/tracepoint.c                              |  3 +-
>   gdb/value.h                                   |  4 +-
>   13 files changed, 366 insertions(+), 11 deletions(-)
>   create mode 100644 gdb/testsuite/gdb.ada/var_shadowing.exp
>   create mode 100644 gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
>   create mode 100755 gdb/testsuite/gdb.base/var-shadowing.c
>   create mode 100755 gdb/testsuite/gdb.base/var-shadowing.exp
>   create mode 100644 gdb/testsuite/gdb.base/var-shadowing2.c
>   create mode 100755 gdb/testsuite/gdb.rust/var_reuse.exp
>   create mode 100755 gdb/testsuite/gdb.rust/var_reuse.rs
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index e4c00143fd1..6efcc5a8dc9 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -8833,6 +8833,21 @@ The optional flag @samp{-q}, which stands for @samp{quiet}, disables
>   printing header information and messages explaining why no local variables
>   have been printed.
>   
> +@smallexample
> +1: int x = 3;
> +2: @{
> +3:       int x = 4; // breakpt
> +4: @}
> +(gdb) info locals
> +x = 4	<file.c:3>
> +x = 3	<file.c:1, shadowed>
> +@end smallexample
> +
> +A variable is shadowed when there's another variable by the same
> +name which is declared within an inner scope (decision block,
> +method, or inner class).  For such cases, its location for the
> +outermost scope is followed by @samp{shadowed}.
> +
>   @item info locals [-q] [-t @var{type_regexp}] [@var{regexp}]
>   Like @kbd{info locals}, but only print the local variables selected
>   with the provided regexp(s).
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index c5e6a815580..f2bdce398ec 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -56,6 +56,7 @@
>   #include "gdbsupport/gdb-safe-ctype.h"
>   #include "gdbsupport/rsp-low.h"
>   #include "inferior.h"
> +#include "include/libiberty.h"
>   
>   /* Chain containing all defined memory-tag subcommands.  */
>   
> @@ -2331,7 +2332,8 @@ clear_dangling_display_expressions (struct objfile *objfile)
>   void
>   print_variable_and_value (const char *name, struct symbol *var,
>   			  frame_info_ptr frame,
> -			  struct ui_file *stream, int indent)
> +			  struct ui_file *stream, int indent,
> +			  bool shadowed, bool printed)
>   {
>   
>     if (!name)
> @@ -2344,6 +2346,7 @@ print_variable_and_value (const char *name, struct symbol *var,
>       {
>         struct value *val;
>         struct value_print_options opts;
> +      const char *file_name = lbasename (var->owner.symtab->filename);
>   
>         /* READ_VAR_VALUE needs a block in order to deal with non-local
>   	 references (i.e. to handle nested functions).  In this context, we
> @@ -2353,6 +2356,12 @@ print_variable_and_value (const char *name, struct symbol *var,
>         get_user_print_options (&opts);
>         opts.deref_ref = true;
>         common_val_print_checked (val, stream, indent, &opts, current_language);
> +
> +      if (shadowed)
> +	/* Print location and shadowed variable information.  */
> +	fprintf_styled (stream, metadata_style.style (),
> +			_("\t<%s:%d%s>"), file_name,
> +			var->line (), printed ? ", shadowed" : "");
>       }
>     catch (const gdb_exception_error &except)
>       {
> diff --git a/gdb/stack.c b/gdb/stack.c
> index ef565445c16..ef8f0f24b39 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -56,6 +56,7 @@
>   #include "cli/cli-option.h"
>   #include "cli/cli-style.h"
>   #include "gdbsupport/buildargv.h"
> +#include <unordered_set>
>   
>   /* The possible choices of "set print frame-arguments", and the value
>      of this setting.  */
> @@ -2211,10 +2212,16 @@ backtrace_command_completer (struct cmd_list_element *ignore,
>   
>   static void
>   iterate_over_block_locals (const struct block *b,
> -			   iterate_over_block_arg_local_vars_cb cb)
> +			   iterate_over_block_arg_local_vars_cb cb,
> +			   const std::unordered_set<std::string> *shadowed_vars,
> +			   std::unordered_set<std::string> &printed_vars)
>   {
>     for (struct symbol *sym : block_iterator_range (b))
>       {
> +      const char *name = sym->print_name ();
> +      bool already_printed = !printed_vars.insert (name).second;
> +      bool shadowed = shadowed_vars->find (name) != shadowed_vars->end ();
> +
>         switch (sym->aclass ())
>   	{
>   	case LOC_CONST:
> @@ -2227,7 +2234,25 @@ iterate_over_block_locals (const struct block *b,
>   	    break;
>   	  if (sym->domain () == COMMON_BLOCK_DOMAIN)
>   	    break;
> -	  cb (sym->print_name (), sym);
> +	  /* Only for C/C++/Fortran/Ada languages, in case of variables
> +	     shadowing print <file:line, shadowed> annotation after
> +	     the superblock variable.  Iteration of block starts from inner
> +	     block which is printed only with location information.  */
> +	  if ((current_language->la_language == language_c
> +	       || current_language->la_language == language_cplus
> +	       || current_language->la_language == language_fortran
> +	       || current_language->la_language == language_ada)
> +	      && shadowed)
> +	    cb (name, sym, true, already_printed);
> +	  /* In case of Rust language it is possible to declare variable with
> +	     same name multiple times and only latest declaration of variable
> +	     is accessible.  So print only the first instance and there is no
> +	     need of printing duplicates.  */
> +	  else if (current_language->la_language == language_rust
> +		   && shadowed && already_printed)
> +	    break;
> +	  else
> +	    cb (name, sym, false, false);
>   	  break;
>   
>   	default:
> @@ -2244,9 +2269,31 @@ void
>   iterate_over_block_local_vars (const struct block *block,
>   			       iterate_over_block_arg_local_vars_cb cb)
>   {
> +  std::unordered_set<std::string> collected_vars, shadowed_vars, printed_vars;
> +  const struct block *orig_block = block;
> +
> +  /* Iterate over all the local variables in a block and store the list of
> +     shadowed variables to later distinguish them from other variables.  */
> +  while (block != nullptr)
> +    {
> +      for (struct symbol *sym : block_iterator_range (block))
> +	{
> +	  if (!sym->is_argument ())
> +	    {
> +	      const char *name = sym->print_name ();
> +	      if (!collected_vars.insert (name).second)
> +		shadowed_vars.insert (name);
> +	    }
> +	}
> +      if (block->function ())
> +	break;
> +      block = block->superblock ();
> +    }
> +
> +  block = orig_block;
>     while (block)
>       {
> -      iterate_over_block_locals (block, cb);
> +      iterate_over_block_locals (block, cb, &shadowed_vars, printed_vars);
>         /* After handling the function's top-level block, stop.  Don't
>   	 continue to its superblock, the block of per-file
>   	 symbols.  */
> @@ -2268,14 +2315,16 @@ struct print_variable_and_value_data
>     struct ui_file *stream;
>     int values_printed;
>   
> -  void operator() (const char *print_name, struct symbol *sym);
> +  void operator() (const char *print_name, struct symbol *sym, bool shadowed,
> +		   bool printed);
>   };
>   
>   /* The callback for the locals and args iterators.  */
>   
>   void
>   print_variable_and_value_data::operator() (const char *print_name,
> -					   struct symbol *sym)
> +					   struct symbol *sym,
> +					   bool shadowed, bool printed)
>   {
>     frame_info_ptr frame;
>   
> @@ -2295,7 +2344,8 @@ print_variable_and_value_data::operator() (const char *print_name,
>         return;
>       }
>   
> -  print_variable_and_value (print_name, sym, frame, stream, num_tabs);
> +  print_variable_and_value (print_name, sym, frame, stream, num_tabs, shadowed,
> +			    printed);
>   
>     /* print_variable_and_value invalidates FRAME.  */
>     frame = NULL;
> @@ -2476,7 +2526,7 @@ iterate_over_block_arg_vars (const struct block *b,
>   	  struct symbol *sym2
>   	    = lookup_symbol_search_name (sym->search_name (),
>   					 b, VAR_DOMAIN).symbol;
> -	  cb (sym->print_name (), sym2);
> +	  cb (sym->print_name (), sym2, false, false);
>   	}
>       }
>   }
> diff --git a/gdb/stack.h b/gdb/stack.h
> index 1b0c2b342a4..72d843b66fb 100644
> --- a/gdb/stack.h
> +++ b/gdb/stack.h
> @@ -24,7 +24,8 @@ gdb::unique_xmalloc_ptr<char> find_frame_funname (frame_info_ptr frame,
>   						  enum language *funlang,
>   						  struct symbol **funcp);
>   
> -typedef gdb::function_view<void (const char *print_name, struct symbol *sym)>
> +typedef gdb::function_view<void (const char *print_name, struct symbol *sym,
> +				 bool shadowed, bool printed)>
>        iterate_over_block_arg_local_vars_cb;
>   
>   void iterate_over_block_arg_vars (const struct block *block,
> diff --git a/gdb/testsuite/gdb.ada/var_shadowing.exp b/gdb/testsuite/gdb.ada/var_shadowing.exp
> new file mode 100644
> index 00000000000..da279da258d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing.exp
> @@ -0,0 +1,38 @@
> +# Copyright 2023 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +load_lib "ada.exp"
> +
> +require allow_ada_tests
> +
> +standard_ada_testfile var_shadowing
> +
> +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug]] != "" } {
> +  return -1
> +}
> +
> +clean_restart ${testfile}
> +
> +set i_level1 [gdb_get_line_number "I-Level1" ${testdir}/var_shadowing.adb]
> +set i_level2 [gdb_get_line_number "I-Level2" ${testdir}/var_shadowing.adb]
> +set i_level3 [gdb_get_line_number "I-Level3" ${testdir}/var_shadowing.adb]
> +set bp_location [gdb_get_line_number "BREAK" ${testdir}/var_shadowing.adb]
> +runto "var_shadowing.adb:$bp_location"
> +
> +gdb_test "info locals" [multi_line \
> +    "i = 111\t<$testfile.adb:$i_level3>"  \
> +    "i = 11\t<$testfile.adb:$i_level2, shadowed>"  \
> +    "i = 1\t<$testfile.adb:$i_level1, shadowed>"  \
> +] "info locals at innermost level"
> diff --git a/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> new file mode 100644
> index 00000000000..93cef5f0d6c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/var_shadowing/var_shadowing.adb
> @@ -0,0 +1,30 @@
> +--  Copyright 2023 Free Software Foundation, Inc.
> +--
> +--  This program is free software; you can redistribute it and/or modify
> +--  it under the terms of the GNU General Public License as published by
> +--  the Free Software Foundation; either version 3 of the License, or
> +--  (at your option) any later version.
> +--
> +--  This program is distributed in the hope that it will be useful,
> +--  but WITHOUT ANY WARRANTY; without even the implied warranty of
> +--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +--  GNU General Public License for more details.
> +--
> +--  You should have received a copy of the GNU General Public License
> +--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +with Ada.Text_IO; use Ada.Text_IO;
> +
> +procedure Varshadow is
> +  I : Integer := 1;  -- I-Level1
> +begin
> +  declare
> +    I : Integer := 11; -- I-Level2
> +  begin
> +    declare
> +      I : Integer := 111; -- I-Level3
> +    begin
> +      Put_Line ("hello");  --  BREAK
> +    end;
> +  end;
> +end;
> diff --git a/gdb/testsuite/gdb.base/var-shadowing.c b/gdb/testsuite/gdb.base/var-shadowing.c
> new file mode 100755
> index 00000000000..18963514bbf
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.c
> @@ -0,0 +1,49 @@
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include <stdlib.h>
> +
> +void
> +shadowing (void)
> +{
> +  int a;  /* bp for entry */
> +  unsigned int val1 = 1;		/* val1-d1 */
> +  unsigned int val2 = 2;		/* val2-d1 */
> +  a = 101;  /* bp for locals 1 */
> +  {
> +    unsigned int val2 = 3;		/* val2-d2 */
> +    unsigned int val3 = 4;		/* val3-d1 */
> +    a = 102;  /* bp for locals 2 */
> +    {
> +      unsigned int val1 = 5;		/* val1-d2 */
> +      a = 103;  /* bp for locals 3 */
> +      {
> +	#include "var-shadowing2.c"
> +	unsigned int val1 = 6;	/* val1-d3 */
> +	unsigned int val2 = 7;	/* val2-d3 */
> +	unsigned int val3 = 8;	/* val3-d2 */
> +	a = 104;  /* bp for locals 4 */
> +      }
> +    }
> +  }
> +  a = 0; /* bp for locals 5 */
> +}
> +
> +int
> +main (void)
> +{
> +  shadowing ();
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/var-shadowing.exp b/gdb/testsuite/gdb.base/var-shadowing.exp
> new file mode 100755
> index 00000000000..c7e1e9eae2e
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing.exp
> @@ -0,0 +1,90 @@
> +# Copyright 2023 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +standard_testfile
> +if [prepare_for_testing "failed to prepare" $testfile $srcfile] {
> +    return -1
> +}
> +
> +if ![runto_main] {
> +    untested "failed to run to main"
> +    return -1
> +}
> +
> +set bp_line1 [gdb_get_line_number "bp for locals 1" ${srcfile}]
> +set bp_line2 [gdb_get_line_number "bp for locals 2" ${srcfile}]
> +set bp_line3 [gdb_get_line_number "bp for locals 3" ${srcfile}]
> +set bp_line4 [gdb_get_line_number "bp for locals 4" ${srcfile}]
> +set bp_line5 [gdb_get_line_number "bp for locals 5" ${srcfile}]
> +
> +set val1_d1 [gdb_get_line_number "val1-d1" ${srcfile}]
> +set val1_d2 [gdb_get_line_number "val1-d2" ${srcfile}]
> +set val1_d3 [gdb_get_line_number "val1-d3" ${srcfile}]
> +set val2_d1 [gdb_get_line_number "val2-d1" ${srcfile}]
> +set val2_d2 [gdb_get_line_number "val2-d2" ${srcfile}]
> +set val2_d3 [gdb_get_line_number "val2-d3" ${srcfile}]
> +set val3_d1 [gdb_get_line_number "val3-d1" ${srcfile}]
> +set val3_d2 [gdb_get_line_number "val3-d2" ${srcfile}]
> +set a_line [gdb_get_line_number "bp for entry" ${srcfile}]
> +
> +gdb_breakpoint $srcfile:$bp_line1
> +gdb_test "continue" ".*bp for locals 1.*" "continue to outermost level"
> +gdb_test "info locals"  [multi_line \
> +    "val1 = 1"  \
> +    "val2 = 2"  \
> +    ] "info locals at outermost level"
> +
> +gdb_breakpoint $srcfile:$bp_line2
> +gdb_test "continue" ".*bp for locals 2.*" "continue to first level"
> +gdb_test "info locals"  [multi_line \
> +    "val2 = 3\t<$srcfile:$val2_d2>"  \
> +    "val3 = 4"  \
> +    "a = 101"   \
> +    "val1 = 1"  \
> +    "val2 = 2\t<$srcfile:$val2_d1, shadowed>"  \
> +    ] "info locals first level"
> +
> +gdb_breakpoint $srcfile:$bp_line3
> +gdb_test "continue" ".*bp for locals 3.*" "continue to second level"
> +gdb_test "info locals" [multi_line \
> +    "val1 = 5\t<$srcfile:$val1_d2>"  \
> +    "val2 = 3\t<$srcfile:$val2_d2>"  \
> +    "val3 = 4"  \
> +    "a = 102"   \
> +    "val1 = 1\t<$srcfile:$val1_d1, shadowed>"  \
> +    "val2 = 2\t<$srcfile:$val2_d1, shadowed>"  \
> +    ] "info locals second level"
> +
> +gdb_breakpoint $srcfile:$bp_line4
> +gdb_test "continue" ".*bp for locals 4.*" "continue to innermost level"
> +gdb_test "info locals" [multi_line \
> +    "a = 999\t<${testfile}2.c:16>" \
> +    "val1 = 6\t<$srcfile:$val1_d3>"  \
> +    "val2 = 7\t<$srcfile:$val2_d3>"  \
> +    "val3 = 8\t<$srcfile:$val3_d2>"  \
> +    "val1 = 5\t<$srcfile:$val1_d2, shadowed>" \
> +    "val2 = 3\t<$srcfile:$val2_d2, shadowed>" \
> +    "val3 = 4\t<$srcfile:$val3_d1, shadowed>" \
> +    "a = 103\t<$srcfile:$a_line, shadowed>"   \
> +    "val1 = 1\t<$srcfile:$val1_d1, shadowed>" \
> +    "val2 = 2\t<$srcfile:$val2_d1, shadowed>" \
> +    ] "info locals at innermost level"
> +
> +gdb_breakpoint $srcfile:$bp_line5
> +gdb_test "continue" ".*bp for locals 5.*" "continue to outermost level last"
> +gdb_test "info locals" [multi_line \
> +    "val1 = 1"  \
> +    "val2 = 2"  \
> +    ] "info locals at outermost level last"
> diff --git a/gdb/testsuite/gdb.base/var-shadowing2.c b/gdb/testsuite/gdb.base/var-shadowing2.c
> new file mode 100644
> index 00000000000..9bc55f95a84
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/var-shadowing2.c
> @@ -0,0 +1,16 @@
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +int a = 999;
> diff --git a/gdb/testsuite/gdb.rust/var_reuse.exp b/gdb/testsuite/gdb.rust/var_reuse.exp
> new file mode 100755
> index 00000000000..f5715f5e0cd
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.exp
> @@ -0,0 +1,34 @@
> +# Copyright 2023 Free Software Foundation, Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +load_lib rust-support.exp
> +require allow_rust_tests
> +require {can_compile rust}
> +
> +standard_testfile .rs
> +if {[prepare_for_testing "failed to prepare" \
> +	$testfile $srcfile {debug rust}]} {
> +    return -1
> +}
> +
> +set line [gdb_get_line_number "set breakpoint here"]
> +if {![runto ${srcfile}:$line]} {
> +    untested "could not run to breakpoint"
> +    return -1
> +}
> +
> +# Wrong local values are shown for rustc version >= 1.73.
> +setup_xfail "*-*-*" "gdb/31079"
> +gdb_test "info local _x" "_x = 12" "print local _x variable"
> diff --git a/gdb/testsuite/gdb.rust/var_reuse.rs b/gdb/testsuite/gdb.rust/var_reuse.rs
> new file mode 100755
> index 00000000000..03be7981ff1
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rust/var_reuse.rs
> @@ -0,0 +1,20 @@
> +// Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +// This program is free software; you can redistribute it and/or modify
> +// it under the terms of the GNU General Public License as published by
> +// the Free Software Foundation; either version 3 of the License, or
> +// (at your option) any later version.
> +//
> +// This program is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +//
> +// You should have received a copy of the GNU General Public License
> +// along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +fn main() {
> +    let _x = 5;
> +    let _x = _x + 7;
> +    let _y = 8;       // set breakpoint here
> +}
> diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
> index 750185341ea..215d726dd77 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -1047,7 +1047,8 @@ collection_list::add_local_symbols (struct gdbarch *gdbarch, CORE_ADDR pc,
>     int count = 0;
>   
>     auto do_collect_symbol = [&] (const char *print_name,
> -				struct symbol *sym)
> +				struct symbol *sym,
> +				bool shadowed, bool printed)
>       {
>         collect_symbol (sym, gdbarch, frame_regno,
>   		      frame_offset, pc, trace_string);
> diff --git a/gdb/value.h b/gdb/value.h
> index e4912717684..f5130bacdac 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -1537,7 +1537,9 @@ extern void print_variable_and_value (const char *name,
>   				      struct symbol *var,
>   				      frame_info_ptr frame,
>   				      struct ui_file *stream,
> -				      int indent);
> +				      int indent,
> +				      bool shadowed,
> +				      bool printed);
>   
>   extern void typedef_print (struct type *type, struct symbol *news,
>   			   struct ui_file *stream);



More information about the Gdb-patches mailing list