public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/6] Make Fortran support respect more `set print' settings
@ 2021-12-11 11:46 Maciej W. Rozycki
  2021-12-11 11:47 ` [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list Maciej W. Rozycki
                   ` (5 more replies)
  0 siblings, 6 replies; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-11 11:46 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Hi,

 This patch series fixes some coding style issues and then makes Fortran 
value printers respect `set print repeats' and `set print array-indexes'.  
A couple of complementing test cases for C/C++ printers is included.

 Patch 3/6 is based on earlier work by Andrew Burgess, though any faults 
with it are entirely mine.

 Regression-tested with a native `x86_64-linux-gnu' configuration.

 Questions, comments, OK to apply?

  Maciej

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

* [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list
  2021-12-11 11:46 [PATCH 0/6] Make Fortran support respect more `set print' settings Maciej W. Rozycki
@ 2021-12-11 11:47 ` Maciej W. Rozycki
  2021-12-15 13:18   ` Andrew Burgess
  2021-12-11 11:47 ` [PATCH 2/6] Avoid redundant operations in `fortran_array_walker' Maciej W. Rozycki
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-11 11:47 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Following our coding convention initialize the `m_ndimensions' member in 
the member initializer list rather than in the body of the constructor 
of the `fortran_array_walker' class.  No functional change.
---
 gdb/f-array-walker.h |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

gdb-fortran-array-walker-m-ndimensions-init.diff
Index: src-upstream/gdb/f-array-walker.h
===================================================================
--- src-upstream.orig/gdb/f-array-walker.h
+++ src-upstream/gdb/f-array-walker.h
@@ -176,10 +176,9 @@ class fortran_array_walker
 			Args... args)
     : m_type (type),
       m_address (address),
-      m_impl (type, address, args...)
-  {
-    m_ndimensions =  calc_f77_array_dims (m_type);
-  }
+      m_impl (type, address, args...),
+      m_ndimensions (calc_f77_array_dims (m_type))
+  { /* Nothing.  */ }
 
   /* Walk the array.  */
   void

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

* [PATCH 2/6] Avoid redundant operations in `fortran_array_walker'
  2021-12-11 11:46 [PATCH 0/6] Make Fortran support respect more `set print' settings Maciej W. Rozycki
  2021-12-11 11:47 ` [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list Maciej W. Rozycki
@ 2021-12-11 11:47 ` Maciej W. Rozycki
  2021-12-15 13:19   ` Andrew Burgess
  2021-12-11 11:47 ` [PATCH 3/6] Respect `set print repeats' with Fortran arrays Maciej W. Rozycki
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-11 11:47 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Move inner dimension's element type determination outside the respective 
loops in `fortran_array_walker'.  The operation is exactly the same with 
each iteration, so there is no point in redoing it for each element and 
while a smart compiler might be able to move it outside the loop it is 
regardless a bad coding style.  No functional change.
---
 gdb/f-array-walker.h |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

gdb-fortran-array-walker-walk-type.diff
Index: src/gdb/f-array-walker.h
===================================================================
--- src.orig/gdb/f-array-walker.h
+++ src/gdb/f-array-walker.h
@@ -208,6 +208,8 @@ class fortran_array_walker
 
     if (nss != m_ndimensions)
       {
+	struct type *subarray_type = TYPE_TARGET_TYPE (check_typedef (type));
+
 	/* For dimensions other than the inner most, walk each element and
 	   recurse while peeling off one more dimension of the array.  */
 	for (LONGEST i = lowerbound;
@@ -218,13 +220,13 @@ class fortran_array_walker
 	    LONGEST new_offset = offset + calc.index_offset (i);
 
 	    /* Now print the lower dimension.  */
-	    struct type *subarray_type
-	      = TYPE_TARGET_TYPE (check_typedef (type));
 	    walk_1 (nss + 1, subarray_type, new_offset, (i == upperbound));
 	  }
       }
     else
       {
+	struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (type));
+
 	/* For the inner most dimension of the array, process each element
 	   within this dimension.  */
 	for (LONGEST i = lowerbound;
@@ -233,7 +235,6 @@ class fortran_array_walker
 	  {
 	    LONGEST elt_off = offset + calc.index_offset (i);
 
-	    struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (type));
 	    if (is_dynamic_type (elt_type))
 	      {
 		CORE_ADDR e_address = m_address + elt_off;

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

* [PATCH 3/6] Respect `set print repeats' with Fortran arrays
  2021-12-11 11:46 [PATCH 0/6] Make Fortran support respect more `set print' settings Maciej W. Rozycki
  2021-12-11 11:47 ` [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list Maciej W. Rozycki
  2021-12-11 11:47 ` [PATCH 2/6] Avoid redundant operations in `fortran_array_walker' Maciej W. Rozycki
@ 2021-12-11 11:47 ` Maciej W. Rozycki
  2021-12-15 15:18   ` Andrew Burgess
  2021-12-11 11:47 ` [PATCH 4/6] Add `set print repeats' tests for C/C++ arrays Maciej W. Rozycki
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-11 11:47 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Implement `set print repeats' handling for Fortran arrays.  Currently 
the setting is ignored and always treated as if no limit was set.

Unlike the generic array walker implemented decades ago the Fortran one 
is a proper C++ class.  Rather than trying to mimic the old walker then, 
which turned out a bit of a challenge where interacting with the `set 
print elements' setting, write it entirely from scratch, by adding an 
extra specialization handler method for processing dimensions other than 
the innermost one and letting the specialization class call the `walk_1' 
method from the handler as it sees fit.  This way repeats can be tracked 
and the next inner dimension recursed into as a need arises only, or 
unconditionally in the base class.

Keep track of the dimension number being handled in the class rather as 
an argument to the walker so that it does not have to be passed across 
by the specialization class.

Use per-dimension element count tracking, needed to terminate processing 
early when the limit set by `set print elements' is hit.  This requires 
extra care too where the limit triggers exactly where another element 
that is a subarray begins.  In that case rather than recursing we need 
to terminate processing or lone `(...)' would be printed.  Additionally 
if the skipped element is the last one in the current dimension we need 
to print `...' by hand, because `continue_walking' won't print it at the 
upper level, because it can see the last element has already been taken 
care of.

Preserve the existing semantics of `set print elements' where the total 
count of the elements handled is matched against the trigger level which 
is unlike with the C/C++ array printer where the per-dimension element 
count is used instead.

Output now looks like:

(gdb) set print repeats 4
(gdb) print array_2d
$1 = ((2, <repeats 5 times>) <repeats 5 times>)
(gdb) set print elements 12
(gdb) print array_2d
$2 = ((2, <repeats 5 times>) (2, <repeats 5 times>) (2, 2, ...) ...)
(gdb) 

for a 5 by 5 array filled with the value of 2.

Amend existing test cases accordingly that rely on the current incorrect 
behavior and explicitly request that there be no limit for printing 
repeated elements there.

Add suitable test cases as well covering sliced arrays in particular.

Co-Authored-By: Andrew Burgess <andrew.burgess@embecosm.com>
---
 gdb/f-array-walker.h                               |   43 ++-
 gdb/f-valprint.c                                   |  236 ++++++++++++++++++++-
 gdb/testsuite/gdb.fortran/array-repeat.exp         |  167 ++++++++++++++
 gdb/testsuite/gdb.fortran/array-repeat.f90         |   50 ++++
 gdb/testsuite/gdb.fortran/array-slices-repeat.f90  |   99 ++++++++
 gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp |    2 
 gdb/testsuite/gdb.fortran/vla-value-sub.exp        |    2 
 7 files changed, 581 insertions(+), 18 deletions(-)

gdb-fortran-set-print-repeats.diff
Index: src/gdb/f-array-walker.h
===================================================================
--- src.orig/gdb/f-array-walker.h
+++ src/gdb/f-array-walker.h
@@ -131,6 +131,18 @@ struct fortran_array_walker_base_impl
   void finish_dimension (bool inner_p, bool last_p)
   { /* Nothing.  */ }
 
+  /* Called when processing dimensions of the array other than the
+     innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
+     the type of the element being extracted, and ELT_OFF is the offset
+     of the element from the start of array being walked, and LAST_P is
+     true only when this is the last element that will be processed in
+     this dimension.  */
+  void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
+			  struct type *elt_type, LONGEST elt_off, bool last_p)
+  {
+    walk_1 (elt_type, elt_off, last_p);
+  }
+
   /* Called when processing the inner most dimension of the array, for
      every element in the array.  ELT_TYPE is the type of the element being
      extracted, and ELT_OFF is the offset of the element from the start of
@@ -177,22 +189,23 @@ class fortran_array_walker
     : m_type (type),
       m_address (address),
       m_impl (type, address, args...),
-      m_ndimensions (calc_f77_array_dims (m_type))
+      m_ndimensions (calc_f77_array_dims (m_type)),
+      m_nss (0)
   { /* Nothing.  */ }
 
   /* Walk the array.  */
   void
   walk ()
   {
-    walk_1 (1, m_type, 0, false);
+    walk_1 (m_type, 0, false);
   }
 
 private:
-  /* The core of the array walking algorithm.  NSS is the current
-     dimension number being processed, TYPE is the type of this dimension,
-     and OFFSET is the offset (in bytes) for the start of this dimension.  */
+  /* The core of the array walking algorithm.  TYPE is the type of
+     the current dimension being processed and OFFSET is the offset
+     (in bytes) for the start of this dimension.  */
   void
-  walk_1 (int nss, struct type *type, int offset, bool last_p)
+  walk_1 (struct type *type, int offset, bool last_p)
   {
     /* Extract the range, and get lower and upper bounds.  */
     struct type *range_type = check_typedef (type)->index_type ();
@@ -204,9 +217,10 @@ class fortran_array_walker
        dimension.  */
     fortran_array_offset_calculator calc (type);
 
-    m_impl.start_dimension (nss == m_ndimensions);
+    m_nss++;
+    m_impl.start_dimension (m_nss == m_ndimensions);
 
-    if (nss != m_ndimensions)
+    if (m_nss != m_ndimensions)
       {
 	struct type *subarray_type = TYPE_TARGET_TYPE (check_typedef (type));
 
@@ -220,7 +234,12 @@ class fortran_array_walker
 	    LONGEST new_offset = offset + calc.index_offset (i);
 
 	    /* Now print the lower dimension.  */
-	    walk_1 (nss + 1, subarray_type, new_offset, (i == upperbound));
+	    m_impl.process_dimension
+	      ([this] (struct type *w_type, int w_offset, bool w_last_p) -> void
+		{
+		  this->walk_1 (w_type, w_offset, w_last_p);
+		},
+	       subarray_type, new_offset, i == upperbound);
 	  }
       }
     else
@@ -245,7 +264,8 @@ class fortran_array_walker
 	  }
       }
 
-    m_impl.finish_dimension (nss == m_ndimensions, last_p || nss == 1);
+    m_impl.finish_dimension (m_nss == m_ndimensions, last_p || m_nss == 1);
+    m_nss--;
   }
 
   /* The array type being processed.  */
@@ -260,6 +280,9 @@ class fortran_array_walker
 
   /* The total number of dimensions in M_TYPE.  */
   int m_ndimensions;
+
+  /* The current dimension number being processed.  */
+  int m_nss;
 };
 
 #endif /* F_ARRAY_WALKER_H */
Index: src/gdb/f-valprint.c
===================================================================
--- src.orig/gdb/f-valprint.c
+++ src/gdb/f-valprint.c
@@ -21,6 +21,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "annotate.h"
 #include "symtab.h"
 #include "gdbtypes.h"
 #include "expression.h"
@@ -96,6 +97,15 @@ f77_get_dynamic_length_of_aggregate (str
     * TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type)));
 }
 
+/* Per-dimension statistics.  */
+
+struct dimension_stats
+{
+  /* Element counter.  */
+  int nelts;
+  bool elts_counted;
+};
+
 /* A class used by FORTRAN_PRINT_ARRAY as a specialisation of the array
    walking template.  This specialisation prints Fortran arrays.  */
 
@@ -117,7 +127,10 @@ class fortran_array_printer_impl : publi
       m_val (val),
       m_stream (stream),
       m_recurse (recurse),
-      m_options (options)
+      m_options (options),
+      m_dimension (0),
+      m_nrepeats (0),
+      m_stats (0)
   { /* Nothing.  */ }
 
   /* Called while iterating over the array bounds.  When SHOULD_CONTINUE is
@@ -128,8 +141,18 @@ class fortran_array_printer_impl : publi
   bool continue_walking (bool should_continue)
   {
     bool cont = should_continue && (m_elts < m_options->print_max);
+
     if (!cont && should_continue)
-      fputs_filtered ("...", m_stream);
+      {
+	if (m_nrepeats)
+	  {
+	    process_outstanding_elements (m_elt_type_prev, m_elt_off_prev);
+	    fputs_filtered (", ", m_stream);
+	    m_nrepeats = 0;
+	  }
+
+	fputs_filtered ("...", m_stream);
+      }
     return cont;
   }
 
@@ -137,6 +160,12 @@ class fortran_array_printer_impl : publi
      inner most dimension then print an opening '(' character.  */
   void start_dimension (bool inner_p)
   {
+    m_dimension++;
+
+    m_elt_type_prev = nullptr;
+    if (m_stats.size () < m_dimension)
+      m_stats.resize (m_dimension);
+
     fputs_filtered ("(", m_stream);
   }
 
@@ -149,22 +178,200 @@ class fortran_array_printer_impl : publi
     fputs_filtered (")", m_stream);
     if (!last_p)
       fputs_filtered (" ", m_stream);
+
+    m_dimension--;
+  }
+
+  /* Called when processing dimensions of the array other than the
+     innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
+     the type of the element being extracted, and ELT_OFF is the offset
+     of the element from the start of array being walked, and LAST_P is
+     true only when this is the last element that will be processed in
+     this dimension.  */
+  void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
+			  struct type *elt_type, LONGEST elt_off, bool last_p)
+  {
+    size_t dim_indx = m_dimension - 1;
+    struct type *elt_type_prev = m_elt_type_prev;
+    LONGEST elt_off_prev = m_elt_off_prev;
+    bool repeated = (m_options->repeat_count_threshold < UINT_MAX
+		     && elt_type_prev != nullptr
+		     && (m_elts + ((m_nrepeats + 1)
+				   * m_stats[dim_indx + 1].nelts)
+			 <= m_options->print_max)
+		     && dimension_contents_eq (m_val, elt_type,
+					       elt_off_prev, elt_off));
+
+    if (repeated)
+      m_nrepeats++;
+    if (!repeated || last_p)
+      {
+	LONGEST nrepeats = m_nrepeats;
+
+	m_nrepeats = 0;
+	if (nrepeats >= m_options->repeat_count_threshold)
+	  {
+	    annotate_elt_rep (nrepeats + 1);
+	    fprintf_filtered (m_stream, "%p[<repeats %s times>%p]",
+			      metadata_style.style ().ptr (),
+			      plongest (nrepeats + 1),
+			      nullptr);
+	    annotate_elt_rep_end ();
+	    if (!repeated)
+	      fputs_filtered (" ", m_stream);
+	    m_elts += nrepeats * m_stats[dim_indx + 1].nelts;
+	  }
+	else
+	  for (LONGEST i = nrepeats; i > 0; i--)
+	    walk_1 (elt_type_prev, elt_off_prev, repeated && i == 1);
+
+	if (!repeated)
+	  {
+	    /* We need to specially handle the case of hitting `print_max'
+	       exactly as recursing would cause lone `(...)' to be printed.
+	       And we need to print `...' by hand if the skipped element
+	       would be the last one processed, because the subsequent call
+	       to `continue_walking' from our caller won't do that.  */
+	    if (m_elts < m_options->print_max)
+	      {
+		walk_1 (elt_type, elt_off, last_p);
+		nrepeats++;
+	      }
+	    else if (last_p)
+	      fputs_filtered ("...", m_stream);
+	  }
+
+	if (!m_stats[dim_indx].elts_counted)
+	  m_stats[dim_indx].nelts += nrepeats * m_stats[dim_indx + 1].nelts;
+      }
+
+    m_elt_type_prev = elt_type;
+    m_elt_off_prev = elt_off;
+
+    if (last_p)
+      m_stats[dim_indx].elts_counted = true;
   }
 
   /* Called to process an element of ELT_TYPE at offset ELT_OFF from the
      start of the parent object.  */
   void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
   {
-    /* Extract the element value from the parent value.  */
-    struct value *e_val
-      = value_from_component (m_val, elt_type, elt_off);
-    common_val_print (e_val, m_stream, m_recurse, m_options, current_language);
-    if (!last_p)
-      fputs_filtered (", ", m_stream);
+    size_t dim_indx = m_dimension - 1;
+    struct type *elt_type_prev = m_elt_type_prev;
+    LONGEST elt_off_prev = m_elt_off_prev;
+    bool repeated = (m_options->repeat_count_threshold < UINT_MAX
+		     && elt_type_prev != nullptr
+		     && value_contents_eq (m_val, elt_off_prev, m_val, elt_off,
+					   TYPE_LENGTH (elt_type)));
+
+    if (repeated)
+      m_nrepeats++;
+    if (!repeated || last_p)
+      {
+	bool printed = false;
+
+	if (m_nrepeats)
+	  {
+	    process_outstanding_elements (elt_type, elt_off_prev);
+	    printed = true;
+	  }
+
+	if (!repeated)
+	  {
+	    /* Extract the element value from the parent value.  */
+	    struct value *e_val
+	      = value_from_component (m_val, elt_type, elt_off);
+
+	    if (printed)
+	      fputs_filtered (", ", m_stream);
+	    common_val_print (e_val, m_stream, m_recurse, m_options,
+			      current_language);
+	  }
+	if (!last_p)
+	  fputs_filtered (", ", m_stream);
+      }
+
+    m_elt_type_prev = elt_type;
+    m_elt_off_prev = elt_off;
     ++m_elts;
+
+    if (last_p && !m_stats[dim_indx].elts_counted)
+      {
+	m_stats[dim_indx].nelts = m_elts;
+	m_stats[dim_indx].elts_counted = true;
+      }
   }
 
 private:
+  /* Called to print outstanding repeated elements of ELT_TYPE starting
+     at offset ELT_OFF from the start of the parent object.  */
+  void process_outstanding_elements (struct type *elt_type, LONGEST elt_off)
+  {
+    LONGEST nrepeats = m_nrepeats;
+
+    m_nrepeats = 0;
+    if (nrepeats >= m_options->repeat_count_threshold)
+      {
+	annotate_elt_rep (nrepeats + 1);
+	fprintf_filtered (m_stream, "%p[<repeats %s times>%p]",
+			  metadata_style.style ().ptr (),
+			  plongest (nrepeats + 1),
+			  nullptr);
+	annotate_elt_rep_end ();
+      }
+    else
+      {
+	/* Extract the element value from the parent value.  */
+	struct value *e_val = value_from_component (m_val, elt_type, elt_off);
+
+	for (LONGEST i = nrepeats; i > 0; i--)
+	  {
+	    common_val_print (e_val, m_stream, m_recurse, m_options,
+			      current_language);
+	    if (i > 1)
+	      fputs_filtered (", ", m_stream);
+	  }
+      }
+  }
+
+  /* Called to compare two VAL elements of ELT_TYPE at offsets OFFSET1
+     and OFFSET2 each.  Handle subarrays recursively, because they may
+     have been sliced and we do not want to compare any memory contents
+     present between the slices requested.  */
+  bool
+  dimension_contents_eq (const struct value *val, struct type *type,
+			 LONGEST offset1, LONGEST offset2)
+  {
+    if (type->code () == TYPE_CODE_ARRAY
+	&& TYPE_TARGET_TYPE (type)->code () != TYPE_CODE_CHAR)
+      {
+ 	/* Extract the range, and get lower and upper bounds.  */
+	struct type *range_type = check_typedef (type)->index_type ();
+	LONGEST lowerbound, upperbound;
+	if (!get_discrete_bounds (range_type, &lowerbound, &upperbound))
+	  error ("failed to get range bounds");
+
+	/* CALC is used to calculate the offsets for each element.  */
+	fortran_array_offset_calculator calc (type);
+
+	struct type *subarray_type = check_typedef (TYPE_TARGET_TYPE (type));
+	for (LONGEST i = lowerbound; i < upperbound + 1; i++)
+	  {
+	    /* Use the index and the stride to work out a new offset.  */
+	    LONGEST index_offset = calc.index_offset (i);
+
+	    if (!dimension_contents_eq (val, subarray_type,
+					offset1 + index_offset,
+					offset2 + index_offset))
+	      return false;
+	  }
+	return true;
+      }
+    else
+      return value_contents_eq (val, offset1, val, offset2,
+				TYPE_LENGTH (type));
+  }
+
   /* The number of elements printed so far.  */
   int m_elts;
 
@@ -180,6 +387,19 @@ class fortran_array_printer_impl : publi
   /* The print control options.  Gives us the maximum number of elements to
      print, and is passed through to each element that we print.  */
   const struct value_print_options *m_options = nullptr;
+
+  /* Dimension tracker.  */
+  LONGEST m_dimension;
+
+  /* Repetition tracker.  */
+  LONGEST m_nrepeats;
+
+  /* Element tracker.  */
+  struct type *m_elt_type_prev;
+  LONGEST m_elt_off_prev;
+
+  /* Per-dimension stats.  */
+  std::vector<struct dimension_stats> m_stats;
 };
 
 /* This function gets called to print a Fortran array.  */
Index: src/gdb/testsuite/gdb.fortran/array-repeat.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.fortran/array-repeat.exp
@@ -0,0 +1,167 @@
+# Copyright 2021 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/>.
+
+# Test the detection and printing of repeated elements in Fortran arrays.
+
+if {[skip_fortran_tests]} { return -1 }
+
+load_lib fortran.exp
+
+# Build up the expected output for each array.
+set a9p9o "(9, 9, 9, 9, 9, 9)"
+set a1p   "(1, 1, 1, 1, 1)"
+set a1p9  "(1, 1, 1, 1, 1, 9)"
+set a2po  "(2, 2, 2, 2, 2)"
+set a2p   "(${a2po} ${a2po} ${a2po} ${a2po} ${a2po})"
+set a2p9o "(2, 2, 2, 2, 2, 9)"
+set a2p9  "(${a2p9o} ${a2p9o} ${a2p9o} ${a2p9o} ${a2p9o} ${a9p9o})"
+set a3po  "(3, 3, 3, 3, 3)"
+set a3p   "(${a3po} ${a3po} ${a3po} ${a3po} ${a3po})"
+set a3p   "(${a3p} ${a3p} ${a3p} ${a3p} ${a3p})"
+set a3p9o "(3, 3, 3, 3, 3, 9)"
+set a3p9  "(${a3p9o} ${a3p9o} ${a3p9o} ${a3p9o} ${a3p9o} ${a9p9o})"
+set a9p9  "(${a9p9o} ${a9p9o} ${a9p9o} ${a9p9o} ${a9p9o} ${a9p9o})"
+set a3p9  "(${a3p9} ${a3p9} ${a3p9} ${a3p9} ${a3p9} ${a9p9})"
+
+# Convert the output into a regexp.
+set r1p   [string_to_regexp $a1p]
+set r1p9  [string_to_regexp $a1p9]
+set r2po  [string_to_regexp $a2po]
+set r2p9o [string_to_regexp $a2p9o]
+set r2p   [string_to_regexp $a2p]
+set r2p9  [string_to_regexp $a2p9]
+set r3po  [string_to_regexp $a3po]
+set r3p9o [string_to_regexp $a3p9o]
+set r3p   [string_to_regexp $a3p]
+set r3p9  [string_to_regexp $a3p9]
+
+set rep5  "<repeats 5 times>"
+set rep6  "<repeats 6 times>"
+
+proc array_repeat { variant } {
+    global testfile srcfile binfile
+    upvar r1p r1p r1p9 r1p9 r2po r2po r2p9o r2p9o r2p r2p r2p9 r2p9
+    upvar r3po r3po r3p9o r3p9o r3p r3p r3p9 r3p9
+    upvar a2po a2po a2p9o a2p9o a3po a3po a3p9o a3p9o
+    upvar rep5 rep5 rep6 rep6
+
+    standard_testfile "${variant}.f90"
+
+    if {[prepare_for_testing ${testfile}.exp ${variant} ${srcfile} \
+	    {debug f90}]} {
+	return -1
+    }
+
+    if {![fortran_runto_main]} {
+	perror "Could not run to main."
+	continue
+    }
+
+    gdb_breakpoint [gdb_get_line_number "Break here"]
+    gdb_continue_to_breakpoint "${variant}"
+
+    with_test_prefix "${variant}: repeats=unlimited, elements=unlimited" {
+	# Check the arrays print as expected.
+	gdb_test_no_output "set print repeats unlimited"
+	gdb_test_no_output "set print elements unlimited"
+
+	gdb_test "print array_1d"  "${r1p}"
+	gdb_test "print array_1d9" "${r1p9}"
+	gdb_test "print array_2d"  "${r2p}"
+	gdb_test "print array_2d9" "${r2p9}"
+	gdb_test "print array_3d"  "${r3p}"
+	gdb_test "print array_3d9" "${r3p9}"
+    }
+
+    with_test_prefix "${variant}: repeats=4, elements=unlimited" {
+	# Now set the repeat limit.
+	gdb_test_no_output "set print repeats 4"
+	gdb_test_no_output "set print elements unlimited"
+
+	gdb_test "print array_1d" \
+	    [string_to_regexp "(1, ${rep5})"]
+	gdb_test "print array_1d9" \
+	    [string_to_regexp "(1, ${rep5}, 9)"]
+	gdb_test "print array_2d" \
+	    [string_to_regexp "((2, ${rep5}) ${rep5})"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "((2, ${rep5}, 9) ${rep5} (9, ${rep6}))"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "(((3, ${rep5}) ${rep5}) ${rep5})"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "(((3, ${rep5}, 9) ${rep5} (9, ${rep6})) ${rep5}\
+				((9, ${rep6}) ${rep6}))"]
+    }
+
+    with_test_prefix "${variant}: repeats=unlimited, elements=12" {
+	# Now set the element limit.
+	gdb_test_no_output "set print repeats unlimited"
+	gdb_test_no_output "set print elements 12"
+
+	gdb_test "print array_1d"  "${r1p}"
+	gdb_test "print array_1d9" "${r1p9}"
+	gdb_test "print array_2d" \
+	    [string_to_regexp "(${a2po} ${a2po} (2, 2, ...) ...)"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "(${a2p9o} ${a2p9o} ...)"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "((${a3po} ${a3po} (3, 3, ...) ...) ...)"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "((${a3p9o} ${a3p9o} ...) ...)"]
+    }
+
+    with_test_prefix "${variant}: repeats=4, elements=12" {
+	# Now set both limits.
+	gdb_test_no_output "set print repeats 4"
+	gdb_test_no_output "set print elements 12"
+
+	gdb_test "print array_1d" \
+	    [string_to_regexp "(1, ${rep5})"]
+	gdb_test "print array_1d9" \
+	    [string_to_regexp "(1, ${rep5}, 9)"]
+	gdb_test "print array_2d" \
+	    [string_to_regexp "((2, ${rep5}) (2, ${rep5}) (2, 2, ...) ...)"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "((2, ${rep5}, 9) (2, ${rep5}, 9) ...)"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "(((3, ${rep5}) (3, ${rep5}) (3, 3, ...) ...)\
+				...)"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "(((3, ${rep5}, 9) (3, ${rep5}, 9) ...) ...)"]
+    }
+
+    with_test_prefix "${variant}: repeats=4, elements=30" {
+	# Now set both limits.
+	gdb_test_no_output "set print repeats 4"
+	gdb_test_no_output "set print elements 30"
+
+	gdb_test "print array_1d" \
+	    [string_to_regexp "(1, ${rep5})"]
+	gdb_test "print array_1d9" \
+	    [string_to_regexp "(1, ${rep5}, 9)"]
+	gdb_test "print array_2d" \
+	    [string_to_regexp "((2, ${rep5}) ${rep5})"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "((2, ${rep5}, 9) ${rep5} ...)"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "(((3, ${rep5}) ${rep5}) ((3, ${rep5}) ...)\
+				...)"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "(((3, ${rep5}, 9) ${rep5} ...) ...)"]
+    }
+}
+
+array_repeat "array-repeat"
+array_repeat "array-slices-repeat"
Index: src/gdb/testsuite/gdb.fortran/array-repeat.f90
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.fortran/array-repeat.f90
@@ -0,0 +1,50 @@
+! Copyright 2021 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/>.
+
+!
+! Start of test program.
+!
+program test
+
+  ! Declare variables used in this test.
+  integer, dimension (-2:2) :: array_1d
+  integer, dimension (-2:3) :: array_1d9
+  integer, dimension (-2:2, -2:2) :: array_2d
+  integer, dimension (-2:3, -2:3) :: array_2d9
+  integer, dimension (-2:2, -2:2, -2:2) :: array_3d
+  integer, dimension (-2:3, -2:3, -2:3) :: array_3d9
+
+  array_1d = 1
+  array_1d9 = 1
+  array_1d9 (3) = 9
+  array_2d = 2
+  array_2d9 = 2
+  array_2d9 (3, :) = 9
+  array_2d9 (:, 3) = 9
+  array_3d = 3
+  array_3d9 = 3
+  array_3d9 (3, :, :) = 9
+  array_3d9 (:, 3, :) = 9
+  array_3d9 (:, :, 3) = 9
+
+  print *, ""           ! Break here
+  print *, array_1d
+  print *, array_1d9
+  print *, array_2d
+  print *, array_2d9
+  print *, array_3d
+  print *, array_3d9
+
+end program test
Index: src/gdb/testsuite/gdb.fortran/array-slices-repeat.f90
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.fortran/array-slices-repeat.f90
@@ -0,0 +1,99 @@
+! Copyright 2021 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/>.
+
+subroutine show (array_1d, array_1d9, array_2d, array_2d9, array_3d, array_3d9)
+  integer, dimension (-2:) :: array_1d
+  integer, dimension (-2:) :: array_1d9
+  integer, dimension (-2:, -2:) :: array_2d
+  integer, dimension (-2:, -2:) :: array_2d9
+  integer, dimension (-2:, -2:, -2:) :: array_3d
+  integer, dimension (-2:, -2:, -2:) :: array_3d9
+
+  print *, ""           ! Break here
+  print *, array_1d
+  print *, array_1d9
+  print *, array_2d
+  print *, array_2d9
+  print *, array_3d
+  print *, array_3d9
+end subroutine show
+
+!
+! Start of test program.
+!
+program test
+  interface
+    subroutine show (array_1d, array_1d9, array_2d, array_2d9, &
+		     array_3d, array_3d9)
+      integer, dimension (:) :: array_1d
+      integer, dimension (:) :: array_1d9
+      integer, dimension (:, :) :: array_2d
+      integer, dimension (:, :) :: array_2d9
+      integer, dimension (:, :, :) :: array_3d
+      integer, dimension (:, :, :) :: array_3d9
+    end subroutine show
+  end interface
+
+  ! Declare variables used in this test.
+  integer, dimension (-8:6) :: array_1d
+  integer, dimension (-8:9) :: array_1d9
+  integer, dimension (-8:6, -8:6) :: array_2d
+  integer, dimension (-8:9, -8:9) :: array_2d9
+  integer, dimension (-8:6, -8:6, -8:6) :: array_3d
+  integer, dimension (-8:9, -8:9, -8:9) :: array_3d9
+
+  integer, parameter :: v6 (6) = [-5, -4, -3, 1, 2, 3]
+  integer, parameter :: v9 (9) = [-5, -4, -3, 1, 2, 3, 7, 8, 9]
+
+  ! Intersperse slices selected with varying data to make sure it is
+  ! correctly ignored for the purpose of repeated element recognition
+  ! in the slices.
+  array_1d = 7
+  array_1d (::3) = 1
+  array_1d9 = 7
+  array_1d9 (::3) = 1
+  array_1d9 (7) = 9
+  array_2d = 7
+  array_2d (:, v6) = 6
+  array_2d (::3, ::3) = 2
+  array_2d9 = 7
+  array_2d9 (:, v9) = 6
+  array_2d9 (::3, ::3) = 2
+  array_2d9 (7, ::3) = 9
+  array_2d9 (::3, 7) = 9
+  array_3d = 7
+  array_3d (:, v6, :) = 6
+  array_3d (:, v6, v6) = 5
+  array_3d (::3, ::3, ::3) = 3
+  array_3d9 = 7
+  array_3d9 (:, v9, :) = 6
+  array_3d9 (:, v9, v9) = 5
+  array_3d9 (::3, ::3, ::3) = 3
+  array_3d9 (7, ::3, ::3) = 9
+  array_3d9 (::3, 7, ::3) = 9
+  array_3d9 (::3, ::3, 7) = 9
+
+  call show (array_1d (::3), array_1d9 (::3), &
+	     array_2d (::3, ::3), array_2d9 (::3, ::3), &
+	     array_3d (::3, ::3, ::3), array_3d9 (::3, ::3, ::3))
+
+  print *, array_1d
+  print *, array_1d9
+  print *, array_2d
+  print *, array_2d9
+  print *, array_3d
+  print *, array_3d9
+
+end program test
Index: src/gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp
+++ src/gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp
@@ -32,6 +32,8 @@ if ![fortran_runto_main] {
 # We need both variants as depending on the arch we optionally may still be
 # executing the caller line or not after `finish'.
 
+gdb_test_no_output "set print repeats unlimited"
+
 gdb_breakpoint [gdb_get_line_number "array2-almost-filled"]
 gdb_continue_to_breakpoint "array2-almost-filled"
 # array2 size is 296352 bytes.
Index: src/gdb/testsuite/gdb.fortran/vla-value-sub.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.fortran/vla-value-sub.exp
+++ src/gdb/testsuite/gdb.fortran/vla-value-sub.exp
@@ -29,6 +29,8 @@ if ![fortran_runto_main] {
 
 # Check the values of VLA's in subroutine can be evaluated correctly
 
+gdb_test_no_output "set print repeats unlimited"
+
 # Try to access values from a fixed array handled as VLA in subroutine.
 gdb_breakpoint [gdb_get_line_number "not-filled"]
 gdb_continue_to_breakpoint "not-filled (1st)"

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

* [PATCH 4/6] Add `set print repeats' tests for C/C++ arrays
  2021-12-11 11:46 [PATCH 0/6] Make Fortran support respect more `set print' settings Maciej W. Rozycki
                   ` (2 preceding siblings ...)
  2021-12-11 11:47 ` [PATCH 3/6] Respect `set print repeats' with Fortran arrays Maciej W. Rozycki
@ 2021-12-11 11:47 ` Maciej W. Rozycki
  2021-12-15 15:33   ` Andrew Burgess
  2021-12-11 11:47 ` [PATCH 5/6] Respect `set print array-indexes' with Fortran arrays Maciej W. Rozycki
  2021-12-11 11:48 ` [PATCH 6/6] Add `set print array-indexes' tests for C/C++ arrays Maciej W. Rozycki
  5 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-11 11:47 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Add `set print repeats' tests for C/C++ arrays, complementing one for 
Fortran arrays and covering the different interpretation of the `set 
print elements' setting in particular where the per-dimension count of 
the elements handled is matched against the trigger rather than the 
total element count as with Fortran arrays.
---
 gdb/testsuite/gdb.base/array-repeat.c   |   63 ++++++++++++++
 gdb/testsuite/gdb.base/array-repeat.exp |  137 +++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.cp/array-repeat.cc    |   64 ++++++++++++++
 gdb/testsuite/gdb.cp/array-repeat.exp   |  139 ++++++++++++++++++++++++++++++++
 4 files changed, 403 insertions(+)
 create mode 100644 gdb/testsuite/gdb.fortran/array-repeat.exp
 create mode 100644 gdb/testsuite/gdb.fortran/array-repeat.f90

gdb-set-print-repeats-test.diff
Index: src/gdb/testsuite/gdb.base/array-repeat.c
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.base/array-repeat.c
@@ -0,0 +1,63 @@
+/* Copyright 2021 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 <stdio.h>
+
+int
+main (void)
+{
+  int array_1d[5];
+  int array_1d9[6];
+  int array_2d[5][5];
+  int array_2d9[6][6];
+  int array_3d[5][5][5];
+  int array_3d9[6][6][6];
+  int i;
+
+  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
+    *(array_1d + i) = 1;
+  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
+    *(array_1d9 + i) = i % 6 == 5 ? 9 : 1;
+  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
+    *(*array_2d + i) = 2;
+  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
+    *(*array_2d9 + i) = i / 6 == 5 || i % 6 == 5 ? 9 : 2;
+  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
+    *(**array_3d + i) = 3;
+  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
+    *(**array_3d9 + i) = i / 6 / 6 == 5 || i / 6 % 6 == 5 || i % 6 == 5 ? 9 : 3;
+
+  printf("\n");						/* Break here */
+  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
+    printf(" %d", *(array_1d + i));
+  printf("\n");
+  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
+    printf(" %d", *(array_1d9 + i));
+  printf("\n");
+  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
+    printf(" %d", *(*array_2d + i));
+  printf("\n");
+  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
+    printf(" %d", *(*array_2d9 + i));
+  printf("\n");
+  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
+    printf(" %d", *(**array_3d + i));
+  printf("\n");
+  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
+    printf(" %d", *(**array_3d9 + i));
+  printf("\n");
+
+  return 0;
+}
Index: src/gdb/testsuite/gdb.base/array-repeat.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.base/array-repeat.exp
@@ -0,0 +1,137 @@
+# Copyright 2021 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/>.
+
+# Test the detection and printing of repeated elements in C arrays.
+
+standard_testfile .c
+
+if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    perror "Could not run to main."
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "Break here"
+
+# Build up the expected output for each array.
+set a9p9o "{9, 9, 9, 9, 9, 9}"
+set a1p   "{1, 1, 1, 1, 1}"
+set a1p9  "{1, 1, 1, 1, 1, 9}"
+set a2po  "{2, 2, 2, 2, 2}"
+set a2p   "{${a2po}, ${a2po}, ${a2po}, ${a2po}, ${a2po}}"
+set a2p9o "{2, 2, 2, 2, 2, 9}"
+set a2p9  "{${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a9p9o}}"
+set a3po  "{3, 3, 3, 3, 3}"
+set a3p   "{${a3po}, ${a3po}, ${a3po}, ${a3po}, ${a3po}}"
+set a3p   "{${a3p}, ${a3p}, ${a3p}, ${a3p}, ${a3p}}"
+set a3p9o "{3, 3, 3, 3, 3, 9}"
+set a3p9  "{${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a9p9o}}"
+set a9p9  "{${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}}"
+set a3p9  "{${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a9p9}}"
+
+# Convert the output into a regexp.
+set r1p   [string_to_regexp $a1p]
+set r1p9  [string_to_regexp $a1p9]
+set r2po  [string_to_regexp $a2po]
+set r2p9o [string_to_regexp $a2p9o]
+set r2p   [string_to_regexp $a2p]
+set r2p9  [string_to_regexp $a2p9]
+set r3po  [string_to_regexp $a3po]
+set r3p9o [string_to_regexp $a3p9o]
+set r3p   [string_to_regexp $a3p]
+set r3p9  [string_to_regexp $a3p9]
+
+set rep5  "<repeats 5 times>"
+set rep6  "<repeats 6 times>"
+
+with_test_prefix "repeats=unlimited, elements=unlimited" {
+    # Check the arrays print as expected.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d"  "${r1p}"
+    gdb_test "print array_1d9" "${r1p9}"
+    gdb_test "print array_2d"  "${r2p}"
+    gdb_test "print array_2d9" "${r2p9}"
+    gdb_test "print array_3d"  "${r3p}"
+    gdb_test "print array_3d9" "${r3p9}"
+}
+
+with_test_prefix "repeats=4, elements=unlimited" {
+    # Now set the repeat limit.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{1 ${rep5}, 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
+			    {{9 ${rep6}} ${rep6}}}"]
+}
+
+with_test_prefix "repeats=unlimited, elements=3" {
+    # Now set the element limit.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements 3"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{1, 1, 1...}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{1, 1, 1...}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
+}
+
+with_test_prefix "repeats=4, elements=12" {
+    # Now set both limits.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements 12"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{1 ${rep5}, 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
+			    {{9 ${rep6}} ${rep6}}}"]
+}
Index: src/gdb/testsuite/gdb.cp/array-repeat.cc
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.cp/array-repeat.cc
@@ -0,0 +1,64 @@
+// Copyright 2021 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 <cstddef>
+#include <iostream>
+
+int
+main ()
+{
+  int array_1d[5];
+  int array_1d9[6];
+  int array_2d[5][5];
+  int array_2d9[6][6];
+  int array_3d[5][5][5];
+  int array_3d9[6][6][6];
+  std::size_t i;
+
+  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
+    *(array_1d + i) = 1;
+  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
+    *(array_1d9 + i) = i % 6 == 5 ? 9 : 1;
+  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
+    *(*array_2d + i) = 2;
+  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
+    *(*array_2d9 + i) = i / 6 == 5 || i % 6 == 5 ? 9 : 2;
+  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
+    *(**array_3d + i) = 3;
+  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
+    *(**array_3d9 + i) = i / 6 / 6 == 5 || i / 6 % 6 == 5 || i % 6 == 5 ? 9 : 3;
+
+  std::cout << "\n";					// Break here
+  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
+    std::cout << " " << *(array_1d + i);
+  std::cout << "\n";
+  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
+    std::cout << " " << *(array_1d9 + i);
+  std::cout << "\n";
+  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
+    std::cout << " " << *(*array_2d + i);
+  std::cout << "\n";
+  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
+    std::cout << " " << *(*array_2d9 + i);
+  std::cout << "\n";
+  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
+    std::cout << " " << *(**array_3d + i);
+  std::cout << "\n";
+  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
+    std::cout << " " << *(**array_3d9 + i);
+  std::cout << "\n";
+
+  return 0;
+}
Index: src/gdb/testsuite/gdb.cp/array-repeat.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.cp/array-repeat.exp
@@ -0,0 +1,139 @@
+# Copyright 2021 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/>.
+
+# Test the detection and printing of repeated elements in C++ arrays.
+
+if {[skip_cplus_tests]} { continue }
+
+standard_testfile .cc
+
+if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    perror "Could not run to main."
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "Break here"
+
+# Build up the expected output for each array.
+set a9p9o "{9, 9, 9, 9, 9, 9}"
+set a1p   "{1, 1, 1, 1, 1}"
+set a1p9  "{1, 1, 1, 1, 1, 9}"
+set a2po  "{2, 2, 2, 2, 2}"
+set a2p   "{${a2po}, ${a2po}, ${a2po}, ${a2po}, ${a2po}}"
+set a2p9o "{2, 2, 2, 2, 2, 9}"
+set a2p9  "{${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a9p9o}}"
+set a3po  "{3, 3, 3, 3, 3}"
+set a3p   "{${a3po}, ${a3po}, ${a3po}, ${a3po}, ${a3po}}"
+set a3p   "{${a3p}, ${a3p}, ${a3p}, ${a3p}, ${a3p}}"
+set a3p9o "{3, 3, 3, 3, 3, 9}"
+set a3p9  "{${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a9p9o}}"
+set a9p9  "{${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}}"
+set a3p9  "{${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a9p9}}"
+
+# Convert the output into a regexp.
+set r1p   [string_to_regexp $a1p]
+set r1p9  [string_to_regexp $a1p9]
+set r2po  [string_to_regexp $a2po]
+set r2p9o [string_to_regexp $a2p9o]
+set r2p   [string_to_regexp $a2p]
+set r2p9  [string_to_regexp $a2p9]
+set r3po  [string_to_regexp $a3po]
+set r3p9o [string_to_regexp $a3p9o]
+set r3p   [string_to_regexp $a3p]
+set r3p9  [string_to_regexp $a3p9]
+
+set rep5  "<repeats 5 times>"
+set rep6  "<repeats 6 times>"
+
+with_test_prefix "repeats=unlimited, elements=unlimited" {
+    # Check the arrays print as expected.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d"  "${r1p}"
+    gdb_test "print array_1d9" "${r1p9}"
+    gdb_test "print array_2d"  "${r2p}"
+    gdb_test "print array_2d9" "${r2p9}"
+    gdb_test "print array_3d"  "${r3p}"
+    gdb_test "print array_3d9" "${r3p9}"
+}
+
+with_test_prefix "repeats=4, elements=unlimited" {
+    # Now set the repeat limit.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{1 ${rep5}, 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
+			    {{9 ${rep6}} ${rep6}}}"]
+}
+
+with_test_prefix "repeats=unlimited, elements=3" {
+    # Now set the element limit.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements 3"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{1, 1, 1...}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{1, 1, 1...}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
+			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
+}
+
+with_test_prefix "repeats=4, elements=12" {
+    # Now set both limits.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements 12"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{1 ${rep5}, 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
+			    {{9 ${rep6}} ${rep6}}}"]
+}

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

* [PATCH 5/6] Respect `set print array-indexes' with Fortran arrays
  2021-12-11 11:46 [PATCH 0/6] Make Fortran support respect more `set print' settings Maciej W. Rozycki
                   ` (3 preceding siblings ...)
  2021-12-11 11:47 ` [PATCH 4/6] Add `set print repeats' tests for C/C++ arrays Maciej W. Rozycki
@ 2021-12-11 11:47 ` Maciej W. Rozycki
  2021-12-15 16:49   ` Andrew Burgess
  2021-12-11 11:48 ` [PATCH 6/6] Add `set print array-indexes' tests for C/C++ arrays Maciej W. Rozycki
  5 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-11 11:47 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Add `set print array-indexes' handling for Fortran arrays.  Currently 
the setting is ignored and indices are never shown.

Keep track of the most recent index handled so that any outstanding 
repeated elements printed when the limit set by `set print elements' is 
hit have the correct index shown.

Output now looks like:

(gdb) set print array-indexes on
(gdb) print array_1d
$1 = ((-2) = 1, (-1) = 1, (0) = 1, (1) = 1, (2) = 1)
(gdb) set print repeats 4
(gdb) set print elements 12
(gdb) print array_2d
$2 = ((-2) = ((-2) = 2, <repeats 5 times>) (-1) = ((-2) = 2, <repeats 5 times>) (0) = ((-2) = 2, (-1) = 2, ...) ...)
(gdb)

for a 5-element vector and a 5 by 5 array filled with the value of 2.
---
 gdb/f-array-walker.h                        |   13 +
 gdb/f-lang.c                                |   20 ++
 gdb/f-lang.h                                |    6 
 gdb/f-valprint.c                            |   40 ++++-
 gdb/testsuite/gdb.fortran/array-indices.exp |  200 ++++++++++++++++++++++++++++
 5 files changed, 266 insertions(+), 13 deletions(-)

gdb-fortran-set-print-array-indexes.diff
Index: src/gdb/f-array-walker.h
===================================================================
--- src.orig/gdb/f-array-walker.h
+++ src/gdb/f-array-walker.h
@@ -138,7 +138,8 @@ struct fortran_array_walker_base_impl
      true only when this is the last element that will be processed in
      this dimension.  */
   void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
-			  struct type *elt_type, LONGEST elt_off, bool last_p)
+			  struct type *elt_type, LONGEST elt_off,
+			  struct type *, LONGEST, bool last_p)
   {
     walk_1 (elt_type, elt_off, last_p);
   }
@@ -162,7 +163,8 @@ struct fortran_array_walker_base_impl
          process_element (TYPE, OFFSET, true);
        finish_dimension (true, true);
      finish_dimension (false, true);  */
-  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
+  void process_element (struct type *elt_type, LONGEST elt_off,
+			struct type *, LONGEST, bool last_p)
   { /* Nothing.  */ }
 };
 
@@ -223,6 +225,8 @@ class fortran_array_walker
     if (m_nss != m_ndimensions)
       {
 	struct type *subarray_type = TYPE_TARGET_TYPE (check_typedef (type));
+	gdb_assert (range_type->code () == TYPE_CODE_RANGE);
+	struct type *index_type = TYPE_TARGET_TYPE (range_type);
 
 	/* For dimensions other than the inner most, walk each element and
 	   recurse while peeling off one more dimension of the array.  */
@@ -239,7 +243,7 @@ class fortran_array_walker
 		{
 		  this->walk_1 (w_type, w_offset, w_last_p);
 		},
-	       subarray_type, new_offset, i == upperbound);
+	       subarray_type, new_offset, index_type, i, i == upperbound);
 	  }
       }
     else
@@ -260,7 +264,8 @@ class fortran_array_walker
 		elt_type = resolve_dynamic_type (elt_type, {}, e_address);
 	      }
 
-	    m_impl.process_element (elt_type, elt_off, (i == upperbound));
+	    m_impl.process_element (elt_type, elt_off, range_type, i,
+				    i == upperbound);
 	  }
       }
 
Index: src/gdb/f-lang.c
===================================================================
--- src.orig/gdb/f-lang.c
+++ src/gdb/f-lang.c
@@ -330,7 +330,8 @@ class fortran_lazy_array_repacker_impl
   /* Create a lazy value in target memory representing a single element,
      then load the element into GDB's memory and copy the contents into the
      destination value.  */
-  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
+  void process_element (struct type *elt_type, LONGEST elt_off,
+			struct type *, LONGEST, bool last_p)
   {
     copy_element_to_dest (value_at_lazy (elt_type, m_addr + elt_off));
   }
@@ -368,7 +369,8 @@ class fortran_array_repacker_impl
   /* Extract an element of ELT_TYPE at offset (M_BASE_OFFSET + ELT_OFF)
      from the content buffer of M_VAL then copy this extracted value into
      the repacked destination value.  */
-  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
+  void process_element (struct type *elt_type, LONGEST elt_off,
+			struct type *, LONGEST, bool last_p)
   {
     struct value *elt
       = value_from_component (m_val, elt_type, (elt_off + m_base_offset));
@@ -1532,6 +1534,20 @@ fortran_structop_operation::evaluate (st
 
 /* See language.h.  */
 
+void
+f_language::print_array_index (struct type *index_type, LONGEST index,
+			       struct ui_file *stream,
+			       const value_print_options *options) const
+{
+  struct value *index_value = value_from_longest (index_type, index);
+
+  fprintf_filtered (stream, "(");
+  value_print (index_value, stream, options);
+  fprintf_filtered (stream, ") = ");
+}
+
+/* See language.h.  */
+
 void
 f_language::language_arch_info (struct gdbarch *gdbarch,
 				struct language_arch_info *lai) const
Index: src/gdb/f-lang.h
===================================================================
--- src.orig/gdb/f-lang.h
+++ src/gdb/f-lang.h
@@ -59,6 +59,12 @@ class f_language : public language_defn
   }
 
   /* See language.h.  */
+  void print_array_index (struct type *index_type,
+			  LONGEST index,
+			  struct ui_file *stream,
+			  const value_print_options *options) const override;
+
+  /* See language.h.  */
   void language_arch_info (struct gdbarch *gdbarch,
 			   struct language_arch_info *lai) const override;
 
Index: src/gdb/f-valprint.c
===================================================================
--- src.orig/gdb/f-valprint.c
+++ src/gdb/f-valprint.c
@@ -185,11 +185,14 @@ class fortran_array_printer_impl : publi
   /* Called when processing dimensions of the array other than the
      innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
      the type of the element being extracted, and ELT_OFF is the offset
-     of the element from the start of array being walked, and LAST_P is
-     true only when this is the last element that will be processed in
-     this dimension.  */
+     of the element from the start of array being walked, INDEX_TYPE
+     and INDEX is the type and the value respectively of the element's
+     index in the dimension currently being walked and LAST_P is true
+     only when this is the last element that will be processed in this
+     dimension.  */
   void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
-			  struct type *elt_type, LONGEST elt_off, bool last_p)
+			  struct type *elt_type, LONGEST elt_off,
+			  struct type *index_type, LONGEST index, bool last_p)
   {
     size_t dim_indx = m_dimension - 1;
     struct type *elt_type_prev = m_elt_type_prev;
@@ -220,10 +223,15 @@ class fortran_array_printer_impl : publi
 	    if (!repeated)
 	      fputs_filtered (" ", m_stream);
 	    m_elts += nrepeats * m_stats[dim_indx + 1].nelts;
+	    m_index += nrepeats;
 	  }
 	else
 	  for (LONGEST i = nrepeats; i > 0; i--)
-	    walk_1 (elt_type_prev, elt_off_prev, repeated && i == 1);
+	    {
+	      maybe_print_array_index (index_type, index - nrepeats + repeated,
+				       m_stream, m_options);
+	      walk_1 (elt_type_prev, elt_off_prev, repeated && i == 1);
+	    }
 
 	if (!repeated)
 	  {
@@ -234,6 +242,8 @@ class fortran_array_printer_impl : publi
 	       to `continue_walking' from our caller won't do that.  */
 	    if (m_elts < m_options->print_max)
 	      {
+		maybe_print_array_index (index_type, index,
+					 m_stream, m_options);
 		walk_1 (elt_type, elt_off, last_p);
 		nrepeats++;
 	      }
@@ -247,14 +257,20 @@ class fortran_array_printer_impl : publi
 
     m_elt_type_prev = elt_type;
     m_elt_off_prev = elt_off;
+    m_index_type = index_type;
+    m_index = index;
 
     if (last_p)
       m_stats[dim_indx].elts_counted = true;
   }
 
   /* Called to process an element of ELT_TYPE at offset ELT_OFF from the
-     start of the parent object.  */
-  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
+     start of the parent object, where INDEX_TYPE and INDEX is the type
+     and the value respectively of the element's index in the dimension
+     currently being walked and LAST_P is true only when this is the last
+     element that will be processed in this dimension.  */
+  void process_element (struct type *elt_type, LONGEST elt_off,
+			struct type *index_type, LONGEST index, bool last_p)
   {
     size_t dim_indx = m_dimension - 1;
     struct type *elt_type_prev = m_elt_type_prev;
@@ -284,6 +300,7 @@ class fortran_array_printer_impl : publi
 
 	    if (printed)
 	      fputs_filtered (", ", m_stream);
+	    maybe_print_array_index (index_type, index, m_stream, m_options);
 	    common_val_print (e_val, m_stream, m_recurse, m_options,
 			      current_language);
 	  }
@@ -293,6 +310,8 @@ class fortran_array_printer_impl : publi
 
     m_elt_type_prev = elt_type;
     m_elt_off_prev = elt_off;
+    m_index_type = index_type;
+    m_index = index;
     ++m_elts;
 
     if (last_p && !m_stats[dim_indx].elts_counted)
@@ -318,6 +337,7 @@ class fortran_array_printer_impl : publi
 			  plongest (nrepeats + 1),
 			  nullptr);
 	annotate_elt_rep_end ();
+	m_index += nrepeats;
       }
     else
       {
@@ -326,6 +346,8 @@ class fortran_array_printer_impl : publi
 
 	for (LONGEST i = nrepeats; i > 0; i--)
 	  {
+	    maybe_print_array_index (m_index_type, m_index - i + 1,
+				     m_stream, m_options);
 	    common_val_print (e_val, m_stream, m_recurse, m_options,
 			      current_language);
 	    if (i > 1)
@@ -398,6 +420,10 @@ class fortran_array_printer_impl : publi
   struct type *m_elt_type_prev;
   LONGEST m_elt_off_prev;
 
+  /* Index type and value tracker.  */
+  struct type *m_index_type;
+  LONGEST m_index;
+
   /* Per-dimension stats.  */
   std::vector<struct dimension_stats> m_stats;
 };
Index: src/gdb/testsuite/gdb.fortran/array-indices.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.fortran/array-indices.exp
@@ -0,0 +1,200 @@
+# Copyright 2021 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/>.
+
+# Test the printing of element indices in Fortran arrays.
+
+if {[skip_fortran_tests]} { return -1 }
+
+load_lib fortran.exp
+
+# Build up the expected output for each array.
+set n0    {(-2)}
+set n1    {(-1)}
+set n2    {(0)}
+set n3    {(1)}
+set n4    {(2)}
+set n5    {(3)}
+set a9p9o "($n0 = 9, $n1 = 9, $n2 = 9, $n3 = 9, $n4 = 9, $n5 = 9)"
+set a1p   "($n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1)"
+set a1p9  "($n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1, $n5 = 9)"
+set a2po  "($n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2)"
+set a2p   "($n0 = ${a2po} $n1 = ${a2po} $n2 = ${a2po} $n3 = ${a2po}\
+	    $n4 = ${a2po})"
+set a2p9o "($n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2, $n5 = 9)"
+set a2p9  "($n0 = ${a2p9o} $n1 = ${a2p9o} $n2 = ${a2p9o} $n3 = ${a2p9o}\
+	    $n4 = ${a2p9o} $n5 = ${a9p9o})"
+set a3po  "($n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3)"
+set a3p   "($n0 = ${a3po} $n1 = ${a3po} $n2 = ${a3po} $n3 = ${a3po}\
+	    $n4 = ${a3po})"
+set a3p   "($n0 = ${a3p} $n1 = ${a3p} $n2 = ${a3p} $n3 = ${a3p} $n4 = ${a3p})"
+set a3p9o "($n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3, $n5 = 9)"
+set a3p9  "($n0 = ${a3p9o} $n1 = ${a3p9o} $n2 = ${a3p9o} $n3 = ${a3p9o}\
+	    $n4 = ${a3p9o} $n5 = ${a9p9o})"
+set a9p9  "($n0 = ${a9p9o} $n1 = ${a9p9o} $n2 = ${a9p9o} $n3 = ${a9p9o}\
+	    $n4 = ${a9p9o} $n5 = ${a9p9o})"
+set a3p9  "($n0 = ${a3p9} $n1 = ${a3p9} $n2 = ${a3p9} $n3 = ${a3p9}\
+	    $n4 = ${a3p9} $n5 = ${a9p9})"
+
+# Convert the output into a regexp.
+set r1p   [string_to_regexp $a1p]
+set r1p9  [string_to_regexp $a1p9]
+set r2po  [string_to_regexp $a2po]
+set r2p9o [string_to_regexp $a2p9o]
+set r2p   [string_to_regexp $a2p]
+set r2p9  [string_to_regexp $a2p9]
+set r3po  [string_to_regexp $a3po]
+set r3p9o [string_to_regexp $a3p9o]
+set r3p   [string_to_regexp $a3p]
+set r3p9  [string_to_regexp $a3p9]
+
+set rep5  "<repeats 5 times>"
+set rep6  "<repeats 6 times>"
+
+proc array_repeat { variant } {
+    global testfile srcfile
+    upvar n0 n0 n1 n1 n2 n2 n5 n5
+    upvar r1p r1p r1p9 r1p9 r2po r2po r2p9o r2p9o r2p r2p r2p9 r2p9
+    upvar r3po r3po r3p9o r3p9o r3p r3p r3p9 r3p9
+    upvar a2po a2po a2p9o a2p9o a3po a3po a3p9o a3p9o
+    upvar rep5 rep5 rep6 rep6
+
+    standard_testfile "${variant}.f90"
+
+    if {[prepare_for_testing ${testfile}.exp ${variant} ${srcfile} \
+	    {debug f90}]} {
+	return -1
+    }
+
+    with_test_prefix "${variant}" {
+	gdb_test_no_output "set print array-indexes on"
+    }
+
+    if {![fortran_runto_main]} {
+	perror "Could not run to main."
+	continue
+    }
+
+    gdb_breakpoint [gdb_get_line_number "Break here"]
+    gdb_continue_to_breakpoint "${variant}"
+
+    with_test_prefix "${variant}: repeats=unlimited, elements=unlimited" {
+	# Check the arrays print as expected.
+	gdb_test_no_output "set print repeats unlimited"
+	gdb_test_no_output "set print elements unlimited"
+
+	gdb_test "print array_1d"  "${r1p}"
+	gdb_test "print array_1d9" "${r1p9}"
+	gdb_test "print array_2d"  "${r2p}"
+	gdb_test "print array_2d9" "${r2p9}"
+	gdb_test "print array_3d"  "${r3p}"
+	gdb_test "print array_3d9" "${r3p9}"
+    }
+
+    with_test_prefix "${variant}: repeats=4, elements=unlimited" {
+	# Now set the repeat limit.
+	gdb_test_no_output "set print repeats 4"
+	gdb_test_no_output "set print elements unlimited"
+
+	gdb_test "print array_1d" \
+	    [string_to_regexp "($n0 = 1, ${rep5})"]
+	gdb_test "print array_1d9" \
+	    [string_to_regexp "($n0 = 1, ${rep5}, $n5 = 9)"]
+	gdb_test "print array_2d" \
+	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}) ${rep5})"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}, $n5 = 9) ${rep5}\
+				$n5 = ($n0 = 9, ${rep6}))"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}) ${rep5})\
+				${rep5})"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}, $n5 = 9)\
+				       ${rep5} $n5 = ($n0 = 9, ${rep6}))\
+				${rep5}\
+				$n5 = ($n0 = ($n0 = 9, ${rep6}) ${rep6}))"]
+    }
+
+    with_test_prefix "${variant}: repeats=unlimited, elements=12" {
+	# Now set the element limit.
+	gdb_test_no_output "set print repeats unlimited"
+	gdb_test_no_output "set print elements 12"
+
+	gdb_test "print array_1d"  "${r1p}"
+	gdb_test "print array_1d9" "${r1p9}"
+	gdb_test "print array_2d" \
+	    [string_to_regexp "($n0 = ${a2po} $n1 = ${a2po}\
+				$n2 = ($n0 = 2, $n1 = 2, ...) ...)"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "($n0 = ${a2p9o} $n1 = ${a2p9o} ...)"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "($n0 = ($n0 = ${a3po} $n1 = ${a3po}\
+				       $n2 = ($n0 = 3, $n1 = 3, ...)\
+				       ...) ...)"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "($n0 = ($n0 = ${a3p9o} $n1 = ${a3p9o} ...)\
+				...)"]
+    }
+
+    with_test_prefix "${variant}: repeats=4, elements=12" {
+	# Now set both limits.
+	gdb_test_no_output "set print repeats 4"
+	gdb_test_no_output "set print elements 12"
+
+	gdb_test "print array_1d" \
+	    [string_to_regexp "($n0 = 1, ${rep5})"]
+	gdb_test "print array_1d9" \
+	    [string_to_regexp "($n0 = 1, ${rep5}, $n5 = 9)"]
+	gdb_test "print array_2d" \
+	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5})\
+				$n1 = ($n0 = 2, ${rep5})\
+				$n2 = ($n0 = 2, $n1 = 2, ...) ...)"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}, $n5 = 9)\
+				$n1 = ($n0 = 2, ${rep5}, $n5 = 9) ...)"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5})\
+				       $n1 = ($n0 = 3, ${rep5})\
+				       $n2 = ($n0 = 3, $n1 = 3, ...) ...) ...)"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}, $n5 = 9)\
+				       $n1 = ($n0 = 3, ${rep5}, $n5 = 9)\
+				       ...) ...)"]
+    }
+
+    with_test_prefix "${variant}: repeats=4, elements=30" {
+	# Now set both limits.
+	gdb_test_no_output "set print repeats 4"
+	gdb_test_no_output "set print elements 30"
+
+	gdb_test "print array_1d" \
+	    [string_to_regexp "($n0 = 1, ${rep5})"]
+	gdb_test "print array_1d9" \
+	    [string_to_regexp "($n0 = 1, ${rep5}, $n5 = 9)"]
+	gdb_test "print array_2d" \
+	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}) ${rep5})"]
+	gdb_test "print array_2d9" \
+	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}, $n5 = 9) ${rep5}\
+				...)"]
+	gdb_test "print array_3d" \
+	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}) ${rep5})\
+				$n1 = ($n0 = ($n0 = 3, ${rep5}) ...) ...)"]
+	gdb_test "print array_3d9" \
+	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}, $n5 = 9)\
+				       ${rep5} ...) ...)"]
+    }
+}
+
+array_repeat "array-repeat"
+array_repeat "array-slices-repeat"

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

* [PATCH 6/6] Add `set print array-indexes' tests for C/C++ arrays
  2021-12-11 11:46 [PATCH 0/6] Make Fortran support respect more `set print' settings Maciej W. Rozycki
                   ` (4 preceding siblings ...)
  2021-12-11 11:47 ` [PATCH 5/6] Respect `set print array-indexes' with Fortran arrays Maciej W. Rozycki
@ 2021-12-11 11:48 ` Maciej W. Rozycki
  2021-12-15 16:51   ` Andrew Burgess
  5 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-11 11:48 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Add `set print array-indexes' tests for C/C++ arrays, complementing one 
for Fortran arrays.
---
 gdb/testsuite/gdb.base/array-indices.exp |  174 ++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.cp/array-indices.exp   |  176 +++++++++++++++++++++++++++++++
 2 files changed, 350 insertions(+)

gdb-set-print-array-indexes-test.diff
Index: src/gdb/testsuite/gdb.base/array-indices.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.base/array-indices.exp
@@ -0,0 +1,174 @@
+# Copyright 2021 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/>.
+
+# Test the printing of element indices in C arrays.
+
+standard_testfile array-repeat.c
+
+if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug}]} {
+    return -1
+}
+
+gdb_test_no_output "set print array-indexes on"
+
+if {![runto_main]} {
+    perror "Could not run to main."
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "Break here"
+
+# Build up the expected output for each array.
+set n0    {[0]}
+set n1    {[1]}
+set n2    {[2]}
+set n3    {[3]}
+set n4    {[4]}
+set n5    {[5]}
+set a9p9o "{$n0 = 9, $n1 = 9, $n2 = 9, $n3 = 9, $n4 = 9, $n5 = 9}"
+set a1p   "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1}"
+set a1p9  "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1, $n5 = 9}"
+set a2po  "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2}"
+set a2p   "{$n0 = ${a2po}, $n1 = ${a2po}, $n2 = ${a2po}, $n3 = ${a2po},\
+	    $n4 = ${a2po}}"
+set a2p9o "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2, $n5 = 9}"
+set a2p9  "{$n0 = ${a2p9o}, $n1 = ${a2p9o}, $n2 = ${a2p9o}, $n3 = ${a2p9o},\
+	    $n4 = ${a2p9o}, $n5 = ${a9p9o}}"
+set a3po  "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3}"
+set a3p   "{$n0 = ${a3po}, $n1 = ${a3po}, $n2 = ${a3po}, $n3 = ${a3po},\
+	    $n4 = ${a3po}}"
+set a3p   "{$n0 = ${a3p}, $n1 = ${a3p}, $n2 = ${a3p}, $n3 = ${a3p},\
+	    $n4 = ${a3p}}"
+set a3p9o "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3, $n5 = 9}"
+set a3p9  "{$n0 = ${a3p9o}, $n1 = ${a3p9o}, $n2 = ${a3p9o}, $n3 = ${a3p9o},\
+	    $n4 = ${a3p9o}, $n5 = ${a9p9o}}"
+set a9p9  "{$n0 = ${a9p9o}, $n1 = ${a9p9o}, $n2 = ${a9p9o}, $n3 = ${a9p9o},\
+	    $n4 = ${a9p9o}, $n5 = ${a9p9o}}"
+set a3p9  "{$n0 = ${a3p9}, $n1 = ${a3p9}, $n2 = ${a3p9}, $n3 = ${a3p9},\
+	    $n4 = ${a3p9}, $n5 = ${a9p9}}"
+
+# Convert the output into a regexp.
+set r1p   [string_to_regexp $a1p]
+set r1p9  [string_to_regexp $a1p9]
+set r2po  [string_to_regexp $a2po]
+set r2p9o [string_to_regexp $a2p9o]
+set r2p   [string_to_regexp $a2p]
+set r2p9  [string_to_regexp $a2p9]
+set r3po  [string_to_regexp $a3po]
+set r3p9o [string_to_regexp $a3p9o]
+set r3p   [string_to_regexp $a3p]
+set r3p9  [string_to_regexp $a3p9]
+
+set rep5  "<repeats 5 times>"
+set rep6  "<repeats 6 times>"
+
+with_test_prefix "repeats=unlimited, elements=unlimited" {
+    # Check the arrays print as expected.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d"  "${r1p}"
+    gdb_test "print array_1d9" "${r1p9}"
+    gdb_test "print array_2d"  "${r2p}"
+    gdb_test "print array_2d9" "${r2p9}"
+    gdb_test "print array_3d"  "${r3p}"
+    gdb_test "print array_3d9" "${r3p9}"
+}
+
+with_test_prefix "repeats=4, elements=unlimited" {
+    # Now set the repeat limit.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{$n0 = 1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
+			    $n5 = {$n0 = 9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
+				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
+			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
+}
+
+with_test_prefix "repeats=unlimited, elements=3" {
+    # Now set the element limit.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements 3"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3,\
+					  $n2 = 3...}...}...}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3,\
+					  $n2 = 3...}...}...}"]
+}
+
+with_test_prefix "repeats=4, elements=12" {
+    # Now set both limits.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements 12"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{$n0 = 1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
+			    $n5 = {$n0 = 9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
+				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
+			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
+}
Index: src/gdb/testsuite/gdb.cp/array-indices.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.cp/array-indices.exp
@@ -0,0 +1,176 @@
+# Copyright 2021 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/>.
+
+# Test the printing of element indices in C++ arrays.
+
+if {[skip_cplus_tests]} { continue }
+
+standard_testfile array-repeat.cc
+
+if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}]} {
+    return -1
+}
+
+gdb_test_no_output "set print array-indexes on"
+
+if {![runto_main]} {
+    perror "Could not run to main."
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "Break here"
+
+# Build up the expected output for each array.
+set n0    {[0]}
+set n1    {[1]}
+set n2    {[2]}
+set n3    {[3]}
+set n4    {[4]}
+set n5    {[5]}
+set a9p9o "{$n0 = 9, $n1 = 9, $n2 = 9, $n3 = 9, $n4 = 9, $n5 = 9}"
+set a1p   "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1}"
+set a1p9  "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1, $n5 = 9}"
+set a2po  "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2}"
+set a2p   "{$n0 = ${a2po}, $n1 = ${a2po}, $n2 = ${a2po}, $n3 = ${a2po},\
+	    $n4 = ${a2po}}"
+set a2p9o "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2, $n5 = 9}"
+set a2p9  "{$n0 = ${a2p9o}, $n1 = ${a2p9o}, $n2 = ${a2p9o}, $n3 = ${a2p9o},\
+	    $n4 = ${a2p9o}, $n5 = ${a9p9o}}"
+set a3po  "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3}"
+set a3p   "{$n0 = ${a3po}, $n1 = ${a3po}, $n2 = ${a3po}, $n3 = ${a3po},\
+	    $n4 = ${a3po}}"
+set a3p   "{$n0 = ${a3p}, $n1 = ${a3p}, $n2 = ${a3p}, $n3 = ${a3p},\
+	    $n4 = ${a3p}}"
+set a3p9o "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3, $n5 = 9}"
+set a3p9  "{$n0 = ${a3p9o}, $n1 = ${a3p9o}, $n2 = ${a3p9o}, $n3 = ${a3p9o},\
+	    $n4 = ${a3p9o}, $n5 = ${a9p9o}}"
+set a9p9  "{$n0 = ${a9p9o}, $n1 = ${a9p9o}, $n2 = ${a9p9o}, $n3 = ${a9p9o},\
+	    $n4 = ${a9p9o}, $n5 = ${a9p9o}}"
+set a3p9  "{$n0 = ${a3p9}, $n1 = ${a3p9}, $n2 = ${a3p9}, $n3 = ${a3p9},\
+	    $n4 = ${a3p9}, $n5 = ${a9p9}}"
+
+# Convert the output into a regexp.
+set r1p   [string_to_regexp $a1p]
+set r1p9  [string_to_regexp $a1p9]
+set r2po  [string_to_regexp $a2po]
+set r2p9o [string_to_regexp $a2p9o]
+set r2p   [string_to_regexp $a2p]
+set r2p9  [string_to_regexp $a2p9]
+set r3po  [string_to_regexp $a3po]
+set r3p9o [string_to_regexp $a3p9o]
+set r3p   [string_to_regexp $a3p]
+set r3p9  [string_to_regexp $a3p9]
+
+set rep5  "<repeats 5 times>"
+set rep6  "<repeats 6 times>"
+
+with_test_prefix "repeats=unlimited, elements=unlimited" {
+    # Check the arrays print as expected.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d"  "${r1p}"
+    gdb_test "print array_1d9" "${r1p9}"
+    gdb_test "print array_2d"  "${r2p}"
+    gdb_test "print array_2d9" "${r2p9}"
+    gdb_test "print array_3d"  "${r3p}"
+    gdb_test "print array_3d9" "${r3p9}"
+}
+
+with_test_prefix "repeats=4, elements=unlimited" {
+    # Now set the repeat limit.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements unlimited"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{$n0 = 1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
+			    $n5 = {$n0 = 9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
+				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
+			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
+}
+
+with_test_prefix "repeats=unlimited, elements=3" {
+    # Now set the element limit.
+    gdb_test_no_output "set print repeats unlimited"
+    gdb_test_no_output "set print elements 3"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
+			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3,\
+					  $n2 = 3...}...}...}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
+			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
+				   $n2 = {$n0 = 3, $n1 = 3,\
+					  $n2 = 3...}...}...}"]
+}
+
+with_test_prefix "repeats=4, elements=12" {
+    # Now set both limits.
+    gdb_test_no_output "set print repeats 4"
+    gdb_test_no_output "set print elements 12"
+
+    gdb_test "print array_1d" \
+	[string_to_regexp "{$n0 = 1 ${rep5}}"]
+    gdb_test "print array_1d9" \
+	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
+    gdb_test "print array_2d" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
+    gdb_test "print array_2d9" \
+	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
+			    $n5 = {$n0 = 9 ${rep6}}}"]
+    gdb_test "print array_3d" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
+    gdb_test "print array_3d9" \
+	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
+				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
+			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
+}

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

* Re: [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list
  2021-12-11 11:47 ` [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list Maciej W. Rozycki
@ 2021-12-15 13:18   ` Andrew Burgess
  2021-12-17 15:03     ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Burgess @ 2021-12-15 13:18 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

* Maciej W. Rozycki <macro@embecosm.com> [2021-12-11 11:47:06 +0000]:

> Following our coding convention initialize the `m_ndimensions' member in 
> the member initializer list rather than in the body of the constructor 
> of the `fortran_array_walker' class.  No functional change.
> ---
>  gdb/f-array-walker.h |    7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)

LGTM.

Thanks,
Andrew

> 
> gdb-fortran-array-walker-m-ndimensions-init.diff
> Index: src-upstream/gdb/f-array-walker.h
> ===================================================================
> --- src-upstream.orig/gdb/f-array-walker.h
> +++ src-upstream/gdb/f-array-walker.h
> @@ -176,10 +176,9 @@ class fortran_array_walker
>  			Args... args)
>      : m_type (type),
>        m_address (address),
> -      m_impl (type, address, args...)
> -  {
> -    m_ndimensions =  calc_f77_array_dims (m_type);
> -  }
> +      m_impl (type, address, args...),
> +      m_ndimensions (calc_f77_array_dims (m_type))
> +  { /* Nothing.  */ }
>  
>    /* Walk the array.  */
>    void
> 


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

* Re: [PATCH 2/6] Avoid redundant operations in `fortran_array_walker'
  2021-12-11 11:47 ` [PATCH 2/6] Avoid redundant operations in `fortran_array_walker' Maciej W. Rozycki
@ 2021-12-15 13:19   ` Andrew Burgess
  2021-12-17 15:04     ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Burgess @ 2021-12-15 13:19 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

* Maciej W. Rozycki <macro@embecosm.com> [2021-12-11 11:47:14 +0000]:

> Move inner dimension's element type determination outside the respective 
> loops in `fortran_array_walker'.  The operation is exactly the same with 
> each iteration, so there is no point in redoing it for each element and 
> while a smart compiler might be able to move it outside the loop it is 
> regardless a bad coding style.  No functional change.

LGTM.

Thanks,
Andrew


> ---
>  gdb/f-array-walker.h |    7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> gdb-fortran-array-walker-walk-type.diff
> Index: src/gdb/f-array-walker.h
> ===================================================================
> --- src.orig/gdb/f-array-walker.h
> +++ src/gdb/f-array-walker.h
> @@ -208,6 +208,8 @@ class fortran_array_walker
>  
>      if (nss != m_ndimensions)
>        {
> +	struct type *subarray_type = TYPE_TARGET_TYPE (check_typedef (type));
> +
>  	/* For dimensions other than the inner most, walk each element and
>  	   recurse while peeling off one more dimension of the array.  */
>  	for (LONGEST i = lowerbound;
> @@ -218,13 +220,13 @@ class fortran_array_walker
>  	    LONGEST new_offset = offset + calc.index_offset (i);
>  
>  	    /* Now print the lower dimension.  */
> -	    struct type *subarray_type
> -	      = TYPE_TARGET_TYPE (check_typedef (type));
>  	    walk_1 (nss + 1, subarray_type, new_offset, (i == upperbound));
>  	  }
>        }
>      else
>        {
> +	struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (type));
> +
>  	/* For the inner most dimension of the array, process each element
>  	   within this dimension.  */
>  	for (LONGEST i = lowerbound;
> @@ -233,7 +235,6 @@ class fortran_array_walker
>  	  {
>  	    LONGEST elt_off = offset + calc.index_offset (i);
>  
> -	    struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (type));
>  	    if (is_dynamic_type (elt_type))
>  	      {
>  		CORE_ADDR e_address = m_address + elt_off;
> 


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

* Re: [PATCH 3/6] Respect `set print repeats' with Fortran arrays
  2021-12-11 11:47 ` [PATCH 3/6] Respect `set print repeats' with Fortran arrays Maciej W. Rozycki
@ 2021-12-15 15:18   ` Andrew Burgess
  2022-01-08 16:25     ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Burgess @ 2021-12-15 15:18 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

* Maciej W. Rozycki <macro@embecosm.com> [2021-12-11 11:47:25 +0000]:

> Implement `set print repeats' handling for Fortran arrays.  Currently 
> the setting is ignored and always treated as if no limit was set.
> 
> Unlike the generic array walker implemented decades ago the Fortran one 
> is a proper C++ class.  Rather than trying to mimic the old walker then, 
> which turned out a bit of a challenge where interacting with the `set 
> print elements' setting, write it entirely from scratch, by adding an 
> extra specialization handler method for processing dimensions other than 
> the innermost one and letting the specialization class call the `walk_1' 
> method from the handler as it sees fit.  This way repeats can be tracked 
> and the next inner dimension recursed into as a need arises only, or 
> unconditionally in the base class.
> 
> Keep track of the dimension number being handled in the class rather as 
> an argument to the walker so that it does not have to be passed across 
> by the specialization class.
> 
> Use per-dimension element count tracking, needed to terminate processing 
> early when the limit set by `set print elements' is hit.  This requires 
> extra care too where the limit triggers exactly where another element 
> that is a subarray begins.  In that case rather than recursing we need 
> to terminate processing or lone `(...)' would be printed.  Additionally 
> if the skipped element is the last one in the current dimension we need 
> to print `...' by hand, because `continue_walking' won't print it at the 
> upper level, because it can see the last element has already been taken 
> care of.
> 
> Preserve the existing semantics of `set print elements' where the total 
> count of the elements handled is matched against the trigger level which 
> is unlike with the C/C++ array printer where the per-dimension element 
> count is used instead.
> 
> Output now looks like:
> 
> (gdb) set print repeats 4
> (gdb) print array_2d
> $1 = ((2, <repeats 5 times>) <repeats 5 times>)
> (gdb) set print elements 12
> (gdb) print array_2d
> $2 = ((2, <repeats 5 times>) (2, <repeats 5 times>) (2, 2, ...) ...)
> (gdb) 
> 
> for a 5 by 5 array filled with the value of 2.
> 
> Amend existing test cases accordingly that rely on the current incorrect 
> behavior and explicitly request that there be no limit for printing 
> repeated elements there.
> 
> Add suitable test cases as well covering sliced arrays in particular.

Thanks for working on this, this looks awesome now.

> 
> Co-Authored-By: Andrew Burgess <andrew.burgess@embecosm.com>

That's a little generous, this work is ~99% yours I think :)

I have some feedback, and a couple of pretty minor questions...

> ---
>  gdb/f-array-walker.h                               |   43 ++-
>  gdb/f-valprint.c                                   |  236 ++++++++++++++++++++-
>  gdb/testsuite/gdb.fortran/array-repeat.exp         |  167 ++++++++++++++
>  gdb/testsuite/gdb.fortran/array-repeat.f90         |   50 ++++
>  gdb/testsuite/gdb.fortran/array-slices-repeat.f90  |   99 ++++++++
>  gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp |    2 
>  gdb/testsuite/gdb.fortran/vla-value-sub.exp        |    2 
>  7 files changed, 581 insertions(+), 18 deletions(-)
> 
> gdb-fortran-set-print-repeats.diff
> Index: src/gdb/f-array-walker.h
> ===================================================================
> --- src.orig/gdb/f-array-walker.h
> +++ src/gdb/f-array-walker.h
> @@ -131,6 +131,18 @@ struct fortran_array_walker_base_impl
>    void finish_dimension (bool inner_p, bool last_p)
>    { /* Nothing.  */ }
>  
> +  /* Called when processing dimensions of the array other than the
> +     innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
> +     the type of the element being extracted, and ELT_OFF is the offset
> +     of the element from the start of array being walked, and LAST_P is
> +     true only when this is the last element that will be processed in
> +     this dimension.  */
> +  void process_dimension (std::function<void (struct type *, int, bool)> walk_1,

I think you should be using gdb::function_view here as the lambda only
needs to live for the lifetime of the function call.

> +			  struct type *elt_type, LONGEST elt_off, bool last_p)
> +  {
> +    walk_1 (elt_type, elt_off, last_p);
> +  }
> +
>    /* Called when processing the inner most dimension of the array, for
>       every element in the array.  ELT_TYPE is the type of the element being
>       extracted, and ELT_OFF is the offset of the element from the start of
> @@ -177,22 +189,23 @@ class fortran_array_walker
>      : m_type (type),
>        m_address (address),
>        m_impl (type, address, args...),
> -      m_ndimensions (calc_f77_array_dims (m_type))
> +      m_ndimensions (calc_f77_array_dims (m_type)),
> +      m_nss (0)
>    { /* Nothing.  */ }
>  
>    /* Walk the array.  */
>    void
>    walk ()
>    {
> -    walk_1 (1, m_type, 0, false);
> +    walk_1 (m_type, 0, false);
>    }
>  
>  private:
> -  /* The core of the array walking algorithm.  NSS is the current
> -     dimension number being processed, TYPE is the type of this dimension,
> -     and OFFSET is the offset (in bytes) for the start of this dimension.  */
> +  /* The core of the array walking algorithm.  TYPE is the type of
> +     the current dimension being processed and OFFSET is the offset
> +     (in bytes) for the start of this dimension.  */
>    void
> -  walk_1 (int nss, struct type *type, int offset, bool last_p)
> +  walk_1 (struct type *type, int offset, bool last_p)
>    {
>      /* Extract the range, and get lower and upper bounds.  */
>      struct type *range_type = check_typedef (type)->index_type ();
> @@ -204,9 +217,10 @@ class fortran_array_walker
>         dimension.  */
>      fortran_array_offset_calculator calc (type);
>  
> -    m_impl.start_dimension (nss == m_ndimensions);
> +    m_nss++;
> +    m_impl.start_dimension (m_nss == m_ndimensions);
>  
> -    if (nss != m_ndimensions)
> +    if (m_nss != m_ndimensions)
>        {
>  	struct type *subarray_type = TYPE_TARGET_TYPE (check_typedef (type));
>  
> @@ -220,7 +234,12 @@ class fortran_array_walker
>  	    LONGEST new_offset = offset + calc.index_offset (i);
>  
>  	    /* Now print the lower dimension.  */
> -	    walk_1 (nss + 1, subarray_type, new_offset, (i == upperbound));
> +	    m_impl.process_dimension
> +	      ([this] (struct type *w_type, int w_offset, bool w_last_p) -> void
> +		{
> +		  this->walk_1 (w_type, w_offset, w_last_p);
> +		},
> +	       subarray_type, new_offset, i == upperbound);
>  	  }
>        }
>      else
> @@ -245,7 +264,8 @@ class fortran_array_walker
>  	  }
>        }
>  
> -    m_impl.finish_dimension (nss == m_ndimensions, last_p || nss == 1);
> +    m_impl.finish_dimension (m_nss == m_ndimensions, last_p || m_nss == 1);
> +    m_nss--;
>    }
>  
>    /* The array type being processed.  */
> @@ -260,6 +280,9 @@ class fortran_array_walker
>  
>    /* The total number of dimensions in M_TYPE.  */
>    int m_ndimensions;
> +
> +  /* The current dimension number being processed.  */
> +  int m_nss;
>  };
>  
>  #endif /* F_ARRAY_WALKER_H */
> Index: src/gdb/f-valprint.c
> ===================================================================
> --- src.orig/gdb/f-valprint.c
> +++ src/gdb/f-valprint.c
> @@ -21,6 +21,7 @@
>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>  
>  #include "defs.h"
> +#include "annotate.h"
>  #include "symtab.h"
>  #include "gdbtypes.h"
>  #include "expression.h"
> @@ -96,6 +97,15 @@ f77_get_dynamic_length_of_aggregate (str
>      * TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type)));
>  }
>  
> +/* Per-dimension statistics.  */
> +
> +struct dimension_stats
> +{
> +  /* Element counter.  */
> +  int nelts;
> +  bool elts_counted;
> +};

The comments here seem to just be repeating the variable names.  Could
we give more information.  e.g. "Element counter", what elements is it
counting, it's per dimension, but, is it counting every element?  The
number of repeated elements in a series?  What does the bool mean?
Does it mean we've counted everything?  Just started counting?

I also wondered about whether we could replace this with, or otherwise
make use of a gdb::optional here?  I see there's one place where we
set elts_counted without appearing to set nelts, I'm guessing we're
picking up the default value of 0 in that case?

> +
>  /* A class used by FORTRAN_PRINT_ARRAY as a specialisation of the array
>     walking template.  This specialisation prints Fortran arrays.  */
>  
> @@ -117,7 +127,10 @@ class fortran_array_printer_impl : publi
>        m_val (val),
>        m_stream (stream),
>        m_recurse (recurse),
> -      m_options (options)
> +      m_options (options),
> +      m_dimension (0),
> +      m_nrepeats (0),
> +      m_stats (0)
>    { /* Nothing.  */ }
>  
>    /* Called while iterating over the array bounds.  When SHOULD_CONTINUE is
> @@ -128,8 +141,18 @@ class fortran_array_printer_impl : publi
>    bool continue_walking (bool should_continue)
>    {
>      bool cont = should_continue && (m_elts < m_options->print_max);
> +
>      if (!cont && should_continue)
> -      fputs_filtered ("...", m_stream);
> +      {
> +	if (m_nrepeats)

The GDB style is to not treat integers as booleans, so this should be
written as:

  if (m_nrepeats > 0)

> +	  {
> +	    process_outstanding_elements (m_elt_type_prev, m_elt_off_prev);
> +	    fputs_filtered (", ", m_stream);
> +	    m_nrepeats = 0;
> +	  }
> +
> +	fputs_filtered ("...", m_stream);
> +      }
>      return cont;
>    }
>  
> @@ -137,6 +160,12 @@ class fortran_array_printer_impl : publi
>       inner most dimension then print an opening '(' character.  */
>    void start_dimension (bool inner_p)
>    {
> +    m_dimension++;
> +
> +    m_elt_type_prev = nullptr;
> +    if (m_stats.size () < m_dimension)
> +      m_stats.resize (m_dimension);
> +
>      fputs_filtered ("(", m_stream);
>    }
>  
> @@ -149,22 +178,200 @@ class fortran_array_printer_impl : publi
>      fputs_filtered (")", m_stream);
>      if (!last_p)
>        fputs_filtered (" ", m_stream);
> +
> +    m_dimension--;
> +  }
> +
> +  /* Called when processing dimensions of the array other than the
> +     innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
> +     the type of the element being extracted, and ELT_OFF is the offset
> +     of the element from the start of array being walked, and LAST_P is
> +     true only when this is the last element that will be processed in
> +     this dimension.  */
> +  void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
> +			  struct type *elt_type, LONGEST elt_off, bool last_p)
> +  {
> +    size_t dim_indx = m_dimension - 1;
> +    struct type *elt_type_prev = m_elt_type_prev;
> +    LONGEST elt_off_prev = m_elt_off_prev;
> +    bool repeated = (m_options->repeat_count_threshold < UINT_MAX
> +		     && elt_type_prev != nullptr
> +		     && (m_elts + ((m_nrepeats + 1)
> +				   * m_stats[dim_indx + 1].nelts)
> +			 <= m_options->print_max)
> +		     && dimension_contents_eq (m_val, elt_type,
> +					       elt_off_prev, elt_off));
> +
> +    if (repeated)
> +      m_nrepeats++;
> +    if (!repeated || last_p)
> +      {
> +	LONGEST nrepeats = m_nrepeats;
> +
> +	m_nrepeats = 0;
> +	if (nrepeats >= m_options->repeat_count_threshold)
> +	  {
> +	    annotate_elt_rep (nrepeats + 1);
> +	    fprintf_filtered (m_stream, "%p[<repeats %s times>%p]",
> +			      metadata_style.style ().ptr (),
> +			      plongest (nrepeats + 1),
> +			      nullptr);
> +	    annotate_elt_rep_end ();
> +	    if (!repeated)
> +	      fputs_filtered (" ", m_stream);
> +	    m_elts += nrepeats * m_stats[dim_indx + 1].nelts;
> +	  }
> +	else
> +	  for (LONGEST i = nrepeats; i > 0; i--)
> +	    walk_1 (elt_type_prev, elt_off_prev, repeated && i == 1);
> +
> +	if (!repeated)
> +	  {
> +	    /* We need to specially handle the case of hitting `print_max'
> +	       exactly as recursing would cause lone `(...)' to be printed.
> +	       And we need to print `...' by hand if the skipped element
> +	       would be the last one processed, because the subsequent call
> +	       to `continue_walking' from our caller won't do that.  */
> +	    if (m_elts < m_options->print_max)
> +	      {
> +		walk_1 (elt_type, elt_off, last_p);
> +		nrepeats++;
> +	      }
> +	    else if (last_p)
> +	      fputs_filtered ("...", m_stream);
> +	  }
> +
> +	if (!m_stats[dim_indx].elts_counted)
> +	  m_stats[dim_indx].nelts += nrepeats * m_stats[dim_indx + 1].nelts;
> +      }
> +
> +    m_elt_type_prev = elt_type;
> +    m_elt_off_prev = elt_off;
> +
> +    if (last_p)
> +      m_stats[dim_indx].elts_counted = true;
>    }
>  
>    /* Called to process an element of ELT_TYPE at offset ELT_OFF from the
>       start of the parent object.  */
>    void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
>    {
> -    /* Extract the element value from the parent value.  */
> -    struct value *e_val
> -      = value_from_component (m_val, elt_type, elt_off);
> -    common_val_print (e_val, m_stream, m_recurse, m_options, current_language);
> -    if (!last_p)
> -      fputs_filtered (", ", m_stream);
> +    size_t dim_indx = m_dimension - 1;
> +    struct type *elt_type_prev = m_elt_type_prev;
> +    LONGEST elt_off_prev = m_elt_off_prev;
> +    bool repeated = (m_options->repeat_count_threshold < UINT_MAX
> +		     && elt_type_prev != nullptr
> +		     && value_contents_eq (m_val, elt_off_prev, m_val, elt_off,
> +					   TYPE_LENGTH (elt_type)));
> +
> +    if (repeated)
> +      m_nrepeats++;
> +    if (!repeated || last_p)
> +      {
> +	bool printed = false;

I noticed that `printed` isn't actually needed, as we could say:

  bool printed = m_nrepeats;

so you could just use m_nrepeats instead.

> +
> +	if (m_nrepeats)

Missing '> 0' again.

> +	  {
> +	    process_outstanding_elements (elt_type, elt_off_prev);
> +	    printed = true;
> +	  }
> +
> +	if (!repeated)
> +	  {
> +	    /* Extract the element value from the parent value.  */
> +	    struct value *e_val
> +	      = value_from_component (m_val, elt_type, elt_off);
> +
> +	    if (printed)
> +	      fputs_filtered (", ", m_stream);
> +	    common_val_print (e_val, m_stream, m_recurse, m_options,
> +			      current_language);
> +	  }
> +	if (!last_p)
> +	  fputs_filtered (", ", m_stream);
> +      }
> +
> +    m_elt_type_prev = elt_type;
> +    m_elt_off_prev = elt_off;
>      ++m_elts;
> +
> +    if (last_p && !m_stats[dim_indx].elts_counted)
> +      {
> +	m_stats[dim_indx].nelts = m_elts;
> +	m_stats[dim_indx].elts_counted = true;
> +      }
>    }
>  
>  private:
> +  /* Called to print outstanding repeated elements of ELT_TYPE starting
> +     at offset ELT_OFF from the start of the parent object.  */
> +  void process_outstanding_elements (struct type *elt_type, LONGEST elt_off)
> +  {
> +    LONGEST nrepeats = m_nrepeats;
> +
> +    m_nrepeats = 0;
> +    if (nrepeats >= m_options->repeat_count_threshold)
> +      {
> +	annotate_elt_rep (nrepeats + 1);
> +	fprintf_filtered (m_stream, "%p[<repeats %s times>%p]",
> +			  metadata_style.style ().ptr (),
> +			  plongest (nrepeats + 1),
> +			  nullptr);
> +	annotate_elt_rep_end ();
> +      }
> +    else
> +      {
> +	/* Extract the element value from the parent value.  */
> +	struct value *e_val = value_from_component (m_val, elt_type, elt_off);
> +
> +	for (LONGEST i = nrepeats; i > 0; i--)
> +	  {
> +	    common_val_print (e_val, m_stream, m_recurse, m_options,
> +			      current_language);
> +	    if (i > 1)
> +	      fputs_filtered (", ", m_stream);
> +	  }
> +      }
> +  }
> +
> +  /* Called to compare two VAL elements of ELT_TYPE at offsets OFFSET1
> +     and OFFSET2 each.  Handle subarrays recursively, because they may
> +     have been sliced and we do not want to compare any memory contents
> +     present between the slices requested.  */
> +  bool
> +  dimension_contents_eq (const struct value *val, struct type *type,
> +			 LONGEST offset1, LONGEST offset2)
> +  {
> +    if (type->code () == TYPE_CODE_ARRAY
> +	&& TYPE_TARGET_TYPE (type)->code () != TYPE_CODE_CHAR)
> +      {
> + 	/* Extract the range, and get lower and upper bounds.  */

You have a space before tab here.

> +	struct type *range_type = check_typedef (type)->index_type ();
> +	LONGEST lowerbound, upperbound;
> +	if (!get_discrete_bounds (range_type, &lowerbound, &upperbound))
> +	  error ("failed to get range bounds");
> +
> +	/* CALC is used to calculate the offsets for each element.  */
> +	fortran_array_offset_calculator calc (type);
> +
> +	struct type *subarray_type = check_typedef (TYPE_TARGET_TYPE (type));
> +	for (LONGEST i = lowerbound; i < upperbound + 1; i++)
> +	  {
> +	    /* Use the index and the stride to work out a new offset.  */
> +	    LONGEST index_offset = calc.index_offset (i);
> +
> +	    if (!dimension_contents_eq (val, subarray_type,
> +					offset1 + index_offset,
> +					offset2 + index_offset))
> +	      return false;
> +	  }
> +	return true;
> +      }
> +    else
> +      return value_contents_eq (val, offset1, val, offset2,
> +				TYPE_LENGTH (type));
> +  }
> +
>    /* The number of elements printed so far.  */
>    int m_elts;
>  
> @@ -180,6 +387,19 @@ class fortran_array_printer_impl : publi
>    /* The print control options.  Gives us the maximum number of elements to
>       print, and is passed through to each element that we print.  */
>    const struct value_print_options *m_options = nullptr;
> +
> +  /* Dimension tracker.  */
> +  LONGEST m_dimension;
> +
> +  /* Repetition tracker.  */
> +  LONGEST m_nrepeats;
> +
> +  /* Element tracker.  */
> +  struct type *m_elt_type_prev;
> +  LONGEST m_elt_off_prev;
> +
> +  /* Per-dimension stats.  */
> +  std::vector<struct dimension_stats> m_stats;

I'd like to see some of these comments expanded slightly to give more
information about how they are used.

>  };
>  
>  /* This function gets called to print a Fortran array.  */
> Index: src/gdb/testsuite/gdb.fortran/array-repeat.exp
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.fortran/array-repeat.exp
> @@ -0,0 +1,167 @@
> +# Copyright 2021 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/>.
> +
> +# Test the detection and printing of repeated elements in Fortran arrays.
> +
> +if {[skip_fortran_tests]} { return -1 }
> +
> +load_lib fortran.exp
> +
> +# Build up the expected output for each array.
> +set a9p9o "(9, 9, 9, 9, 9, 9)"
> +set a1p   "(1, 1, 1, 1, 1)"
> +set a1p9  "(1, 1, 1, 1, 1, 9)"
> +set a2po  "(2, 2, 2, 2, 2)"
> +set a2p   "(${a2po} ${a2po} ${a2po} ${a2po} ${a2po})"
> +set a2p9o "(2, 2, 2, 2, 2, 9)"
> +set a2p9  "(${a2p9o} ${a2p9o} ${a2p9o} ${a2p9o} ${a2p9o} ${a9p9o})"
> +set a3po  "(3, 3, 3, 3, 3)"
> +set a3p   "(${a3po} ${a3po} ${a3po} ${a3po} ${a3po})"
> +set a3p   "(${a3p} ${a3p} ${a3p} ${a3p} ${a3p})"
> +set a3p9o "(3, 3, 3, 3, 3, 9)"
> +set a3p9  "(${a3p9o} ${a3p9o} ${a3p9o} ${a3p9o} ${a3p9o} ${a9p9o})"
> +set a9p9  "(${a9p9o} ${a9p9o} ${a9p9o} ${a9p9o} ${a9p9o} ${a9p9o})"
> +set a3p9  "(${a3p9} ${a3p9} ${a3p9} ${a3p9} ${a3p9} ${a9p9})"
> +
> +# Convert the output into a regexp.
> +set r1p   [string_to_regexp $a1p]
> +set r1p9  [string_to_regexp $a1p9]
> +set r2po  [string_to_regexp $a2po]
> +set r2p9o [string_to_regexp $a2p9o]
> +set r2p   [string_to_regexp $a2p]
> +set r2p9  [string_to_regexp $a2p9]
> +set r3po  [string_to_regexp $a3po]
> +set r3p9o [string_to_regexp $a3p9o]
> +set r3p   [string_to_regexp $a3p]
> +set r3p9  [string_to_regexp $a3p9]
> +
> +set rep5  "<repeats 5 times>"
> +set rep6  "<repeats 6 times>"
> +
> +proc array_repeat { variant } {
> +    global testfile srcfile binfile
> +    upvar r1p r1p r1p9 r1p9 r2po r2po r2p9o r2p9o r2p r2p r2p9 r2p9
> +    upvar r3po r3po r3p9o r3p9o r3p r3p r3p9 r3p9
> +    upvar a2po a2po a2p9o a2p9o a3po a3po a3p9o a3p9o
> +    upvar rep5 rep5 rep6 rep6
> +
> +    standard_testfile "${variant}.f90"
> +
> +    if {[prepare_for_testing ${testfile}.exp ${variant} ${srcfile} \
> +	    {debug f90}]} {
> +	return -1
> +    }
> +
> +    if {![fortran_runto_main]} {
> +	perror "Could not run to main."
> +	continue
> +    }
> +
> +    gdb_breakpoint [gdb_get_line_number "Break here"]
> +    gdb_continue_to_breakpoint "${variant}"
> +
> +    with_test_prefix "${variant}: repeats=unlimited, elements=unlimited" {
> +	# Check the arrays print as expected.
> +	gdb_test_no_output "set print repeats unlimited"
> +	gdb_test_no_output "set print elements unlimited"
> +
> +	gdb_test "print array_1d"  "${r1p}"
> +	gdb_test "print array_1d9" "${r1p9}"
> +	gdb_test "print array_2d"  "${r2p}"
> +	gdb_test "print array_2d9" "${r2p9}"
> +	gdb_test "print array_3d"  "${r3p}"
> +	gdb_test "print array_3d9" "${r3p9}"
> +    }
> +
> +    with_test_prefix "${variant}: repeats=4, elements=unlimited" {
> +	# Now set the repeat limit.
> +	gdb_test_no_output "set print repeats 4"
> +	gdb_test_no_output "set print elements unlimited"
> +
> +	gdb_test "print array_1d" \
> +	    [string_to_regexp "(1, ${rep5})"]
> +	gdb_test "print array_1d9" \
> +	    [string_to_regexp "(1, ${rep5}, 9)"]
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "((2, ${rep5}) ${rep5})"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "((2, ${rep5}, 9) ${rep5} (9, ${rep6}))"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "(((3, ${rep5}) ${rep5}) ${rep5})"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "(((3, ${rep5}, 9) ${rep5} (9, ${rep6})) ${rep5}\
> +				((9, ${rep6}) ${rep6}))"]
> +    }
> +
> +    with_test_prefix "${variant}: repeats=unlimited, elements=12" {
> +	# Now set the element limit.
> +	gdb_test_no_output "set print repeats unlimited"
> +	gdb_test_no_output "set print elements 12"
> +
> +	gdb_test "print array_1d"  "${r1p}"
> +	gdb_test "print array_1d9" "${r1p9}"
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "(${a2po} ${a2po} (2, 2, ...) ...)"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "(${a2p9o} ${a2p9o} ...)"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "((${a3po} ${a3po} (3, 3, ...) ...) ...)"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "((${a3p9o} ${a3p9o} ...) ...)"]
> +    }
> +
> +    with_test_prefix "${variant}: repeats=4, elements=12" {
> +	# Now set both limits.
> +	gdb_test_no_output "set print repeats 4"
> +	gdb_test_no_output "set print elements 12"
> +
> +	gdb_test "print array_1d" \
> +	    [string_to_regexp "(1, ${rep5})"]
> +	gdb_test "print array_1d9" \
> +	    [string_to_regexp "(1, ${rep5}, 9)"]
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "((2, ${rep5}) (2, ${rep5}) (2, 2, ...) ...)"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "((2, ${rep5}, 9) (2, ${rep5}, 9) ...)"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "(((3, ${rep5}) (3, ${rep5}) (3, 3, ...) ...)\
> +				...)"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "(((3, ${rep5}, 9) (3, ${rep5}, 9) ...) ...)"]
> +    }
> +
> +    with_test_prefix "${variant}: repeats=4, elements=30" {
> +	# Now set both limits.
> +	gdb_test_no_output "set print repeats 4"
> +	gdb_test_no_output "set print elements 30"
> +
> +	gdb_test "print array_1d" \
> +	    [string_to_regexp "(1, ${rep5})"]
> +	gdb_test "print array_1d9" \
> +	    [string_to_regexp "(1, ${rep5}, 9)"]
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "((2, ${rep5}) ${rep5})"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "((2, ${rep5}, 9) ${rep5} ...)"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "(((3, ${rep5}) ${rep5}) ((3, ${rep5}) ...)\
> +				...)"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "(((3, ${rep5}, 9) ${rep5} ...) ...)"]
> +    }
> +}
> +
> +array_repeat "array-repeat"
> +array_repeat "array-slices-repeat"
> Index: src/gdb/testsuite/gdb.fortran/array-repeat.f90
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.fortran/array-repeat.f90
> @@ -0,0 +1,50 @@
> +! Copyright 2021 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/>.
> +
> +!
> +! Start of test program.
> +!
> +program test
> +
> +  ! Declare variables used in this test.
> +  integer, dimension (-2:2) :: array_1d
> +  integer, dimension (-2:3) :: array_1d9
> +  integer, dimension (-2:2, -2:2) :: array_2d
> +  integer, dimension (-2:3, -2:3) :: array_2d9
> +  integer, dimension (-2:2, -2:2, -2:2) :: array_3d
> +  integer, dimension (-2:3, -2:3, -2:3) :: array_3d9
> +
> +  array_1d = 1
> +  array_1d9 = 1
> +  array_1d9 (3) = 9
> +  array_2d = 2
> +  array_2d9 = 2
> +  array_2d9 (3, :) = 9
> +  array_2d9 (:, 3) = 9
> +  array_3d = 3
> +  array_3d9 = 3
> +  array_3d9 (3, :, :) = 9
> +  array_3d9 (:, 3, :) = 9
> +  array_3d9 (:, :, 3) = 9
> +
> +  print *, ""           ! Break here
> +  print *, array_1d
> +  print *, array_1d9
> +  print *, array_2d
> +  print *, array_2d9
> +  print *, array_3d
> +  print *, array_3d9
> +
> +end program test
> Index: src/gdb/testsuite/gdb.fortran/array-slices-repeat.f90
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.fortran/array-slices-repeat.f90
> @@ -0,0 +1,99 @@
> +! Copyright 2021 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/>.
> +
> +subroutine show (array_1d, array_1d9, array_2d, array_2d9, array_3d, array_3d9)
> +  integer, dimension (-2:) :: array_1d
> +  integer, dimension (-2:) :: array_1d9
> +  integer, dimension (-2:, -2:) :: array_2d
> +  integer, dimension (-2:, -2:) :: array_2d9
> +  integer, dimension (-2:, -2:, -2:) :: array_3d
> +  integer, dimension (-2:, -2:, -2:) :: array_3d9
> +
> +  print *, ""           ! Break here
> +  print *, array_1d
> +  print *, array_1d9
> +  print *, array_2d
> +  print *, array_2d9
> +  print *, array_3d
> +  print *, array_3d9
> +end subroutine show
> +
> +!
> +! Start of test program.
> +!
> +program test
> +  interface
> +    subroutine show (array_1d, array_1d9, array_2d, array_2d9, &
> +		     array_3d, array_3d9)
> +      integer, dimension (:) :: array_1d
> +      integer, dimension (:) :: array_1d9
> +      integer, dimension (:, :) :: array_2d
> +      integer, dimension (:, :) :: array_2d9
> +      integer, dimension (:, :, :) :: array_3d
> +      integer, dimension (:, :, :) :: array_3d9
> +    end subroutine show
> +  end interface
> +
> +  ! Declare variables used in this test.
> +  integer, dimension (-8:6) :: array_1d
> +  integer, dimension (-8:9) :: array_1d9
> +  integer, dimension (-8:6, -8:6) :: array_2d
> +  integer, dimension (-8:9, -8:9) :: array_2d9
> +  integer, dimension (-8:6, -8:6, -8:6) :: array_3d
> +  integer, dimension (-8:9, -8:9, -8:9) :: array_3d9
> +
> +  integer, parameter :: v6 (6) = [-5, -4, -3, 1, 2, 3]
> +  integer, parameter :: v9 (9) = [-5, -4, -3, 1, 2, 3, 7, 8, 9]
> +
> +  ! Intersperse slices selected with varying data to make sure it is
> +  ! correctly ignored for the purpose of repeated element recognition
> +  ! in the slices.
> +  array_1d = 7
> +  array_1d (::3) = 1
> +  array_1d9 = 7
> +  array_1d9 (::3) = 1
> +  array_1d9 (7) = 9
> +  array_2d = 7
> +  array_2d (:, v6) = 6
> +  array_2d (::3, ::3) = 2
> +  array_2d9 = 7
> +  array_2d9 (:, v9) = 6
> +  array_2d9 (::3, ::3) = 2
> +  array_2d9 (7, ::3) = 9
> +  array_2d9 (::3, 7) = 9
> +  array_3d = 7
> +  array_3d (:, v6, :) = 6
> +  array_3d (:, v6, v6) = 5
> +  array_3d (::3, ::3, ::3) = 3
> +  array_3d9 = 7
> +  array_3d9 (:, v9, :) = 6
> +  array_3d9 (:, v9, v9) = 5
> +  array_3d9 (::3, ::3, ::3) = 3
> +  array_3d9 (7, ::3, ::3) = 9
> +  array_3d9 (::3, 7, ::3) = 9
> +  array_3d9 (::3, ::3, 7) = 9
> +
> +  call show (array_1d (::3), array_1d9 (::3), &
> +	     array_2d (::3, ::3), array_2d9 (::3, ::3), &
> +	     array_3d (::3, ::3, ::3), array_3d9 (::3, ::3, ::3))
> +
> +  print *, array_1d
> +  print *, array_1d9
> +  print *, array_2d
> +  print *, array_2d9
> +  print *, array_3d
> +  print *, array_3d9
> +
> +end program test
> Index: src/gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp
> +++ src/gdb/testsuite/gdb.fortran/vla-value-sub-finish.exp
> @@ -32,6 +32,8 @@ if ![fortran_runto_main] {
>  # We need both variants as depending on the arch we optionally may still be
>  # executing the caller line or not after `finish'.
>  
> +gdb_test_no_output "set print repeats unlimited"
> +
>  gdb_breakpoint [gdb_get_line_number "array2-almost-filled"]
>  gdb_continue_to_breakpoint "array2-almost-filled"
>  # array2 size is 296352 bytes.
> Index: src/gdb/testsuite/gdb.fortran/vla-value-sub.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.fortran/vla-value-sub.exp
> +++ src/gdb/testsuite/gdb.fortran/vla-value-sub.exp
> @@ -29,6 +29,8 @@ if ![fortran_runto_main] {
>  
>  # Check the values of VLA's in subroutine can be evaluated correctly
>  
> +gdb_test_no_output "set print repeats unlimited"
> +
>  # Try to access values from a fixed array handled as VLA in subroutine.
>  gdb_breakpoint [gdb_get_line_number "not-filled"]
>  gdb_continue_to_breakpoint "not-filled (1st)"
> 


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

* Re: [PATCH 4/6] Add `set print repeats' tests for C/C++ arrays
  2021-12-11 11:47 ` [PATCH 4/6] Add `set print repeats' tests for C/C++ arrays Maciej W. Rozycki
@ 2021-12-15 15:33   ` Andrew Burgess
  2022-01-08 16:26     ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Burgess @ 2021-12-15 15:33 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

* Maciej W. Rozycki <macro@embecosm.com> [2021-12-11 11:47:34 +0000]:

> Add `set print repeats' tests for C/C++ arrays, complementing one for 
> Fortran arrays and covering the different interpretation of the `set 
> print elements' setting in particular where the per-dimension count of 
> the elements handled is matched against the trigger rather than the 
> total element count as with Fortran arrays.

I know we disagree on this topic, but I would, one day, like to see
the C/C++ array printing behave as the Fortran array printing does, as
that makes much more sense to me.

But, adding tests for GDB's current behaviour is definitely a good
thing, so I'm happy to see this going in, with one change...

Given that the C and C++ tests are almost identical, I think you
should consider just adding one copy in gdb.base and compiling it as
both C and C++.

For inspiration you can look at these files:

  gdb/testsuite/gdb.base/infcall-nested-structs-c.exp
  gdb/testsuite/gdb.base/infcall-nested-structs-c++.exp
  gdb/testsuite/gdb.base/infcall-nested-structs.exp.tcl

Thanks,
Andrew

> ---
>  gdb/testsuite/gdb.base/array-repeat.c   |   63 ++++++++++++++
>  gdb/testsuite/gdb.base/array-repeat.exp |  137 +++++++++++++++++++++++++++++++
>  gdb/testsuite/gdb.cp/array-repeat.cc    |   64 ++++++++++++++
>  gdb/testsuite/gdb.cp/array-repeat.exp   |  139 ++++++++++++++++++++++++++++++++
>  4 files changed, 403 insertions(+)
>  create mode 100644 gdb/testsuite/gdb.fortran/array-repeat.exp
>  create mode 100644 gdb/testsuite/gdb.fortran/array-repeat.f90
> 
> gdb-set-print-repeats-test.diff
> Index: src/gdb/testsuite/gdb.base/array-repeat.c
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.base/array-repeat.c
> @@ -0,0 +1,63 @@
> +/* Copyright 2021 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 <stdio.h>
> +
> +int
> +main (void)
> +{
> +  int array_1d[5];
> +  int array_1d9[6];
> +  int array_2d[5][5];
> +  int array_2d9[6][6];
> +  int array_3d[5][5][5];
> +  int array_3d9[6][6][6];
> +  int i;
> +
> +  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
> +    *(array_1d + i) = 1;
> +  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
> +    *(array_1d9 + i) = i % 6 == 5 ? 9 : 1;
> +  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
> +    *(*array_2d + i) = 2;
> +  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
> +    *(*array_2d9 + i) = i / 6 == 5 || i % 6 == 5 ? 9 : 2;
> +  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
> +    *(**array_3d + i) = 3;
> +  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
> +    *(**array_3d9 + i) = i / 6 / 6 == 5 || i / 6 % 6 == 5 || i % 6 == 5 ? 9 : 3;
> +
> +  printf("\n");						/* Break here */
> +  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
> +    printf(" %d", *(array_1d + i));
> +  printf("\n");
> +  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
> +    printf(" %d", *(array_1d9 + i));
> +  printf("\n");
> +  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
> +    printf(" %d", *(*array_2d + i));
> +  printf("\n");
> +  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
> +    printf(" %d", *(*array_2d9 + i));
> +  printf("\n");
> +  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
> +    printf(" %d", *(**array_3d + i));
> +  printf("\n");
> +  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
> +    printf(" %d", *(**array_3d9 + i));
> +  printf("\n");
> +
> +  return 0;
> +}
> Index: src/gdb/testsuite/gdb.base/array-repeat.exp
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.base/array-repeat.exp
> @@ -0,0 +1,137 @@
> +# Copyright 2021 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/>.
> +
> +# Test the detection and printing of repeated elements in C arrays.
> +
> +standard_testfile .c
> +
> +if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug}]} {
> +    return -1
> +}
> +
> +if {![runto_main]} {
> +    perror "Could not run to main."
> +    continue
> +}
> +
> +gdb_breakpoint [gdb_get_line_number "Break here"]
> +gdb_continue_to_breakpoint "Break here"
> +
> +# Build up the expected output for each array.
> +set a9p9o "{9, 9, 9, 9, 9, 9}"
> +set a1p   "{1, 1, 1, 1, 1}"
> +set a1p9  "{1, 1, 1, 1, 1, 9}"
> +set a2po  "{2, 2, 2, 2, 2}"
> +set a2p   "{${a2po}, ${a2po}, ${a2po}, ${a2po}, ${a2po}}"
> +set a2p9o "{2, 2, 2, 2, 2, 9}"
> +set a2p9  "{${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a9p9o}}"
> +set a3po  "{3, 3, 3, 3, 3}"
> +set a3p   "{${a3po}, ${a3po}, ${a3po}, ${a3po}, ${a3po}}"
> +set a3p   "{${a3p}, ${a3p}, ${a3p}, ${a3p}, ${a3p}}"
> +set a3p9o "{3, 3, 3, 3, 3, 9}"
> +set a3p9  "{${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a9p9o}}"
> +set a9p9  "{${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}}"
> +set a3p9  "{${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a9p9}}"
> +
> +# Convert the output into a regexp.
> +set r1p   [string_to_regexp $a1p]
> +set r1p9  [string_to_regexp $a1p9]
> +set r2po  [string_to_regexp $a2po]
> +set r2p9o [string_to_regexp $a2p9o]
> +set r2p   [string_to_regexp $a2p]
> +set r2p9  [string_to_regexp $a2p9]
> +set r3po  [string_to_regexp $a3po]
> +set r3p9o [string_to_regexp $a3p9o]
> +set r3p   [string_to_regexp $a3p]
> +set r3p9  [string_to_regexp $a3p9]
> +
> +set rep5  "<repeats 5 times>"
> +set rep6  "<repeats 6 times>"
> +
> +with_test_prefix "repeats=unlimited, elements=unlimited" {
> +    # Check the arrays print as expected.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d"  "${r1p}"
> +    gdb_test "print array_1d9" "${r1p9}"
> +    gdb_test "print array_2d"  "${r2p}"
> +    gdb_test "print array_2d9" "${r2p9}"
> +    gdb_test "print array_3d"  "${r3p}"
> +    gdb_test "print array_3d9" "${r3p9}"
> +}
> +
> +with_test_prefix "repeats=4, elements=unlimited" {
> +    # Now set the repeat limit.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{1 ${rep5}, 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
> +			    {{9 ${rep6}} ${rep6}}}"]
> +}
> +
> +with_test_prefix "repeats=unlimited, elements=3" {
> +    # Now set the element limit.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements 3"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{1, 1, 1...}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{1, 1, 1...}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
> +}
> +
> +with_test_prefix "repeats=4, elements=12" {
> +    # Now set both limits.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements 12"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{1 ${rep5}, 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
> +			    {{9 ${rep6}} ${rep6}}}"]
> +}
> Index: src/gdb/testsuite/gdb.cp/array-repeat.cc
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.cp/array-repeat.cc
> @@ -0,0 +1,64 @@
> +// Copyright 2021 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 <cstddef>
> +#include <iostream>
> +
> +int
> +main ()
> +{
> +  int array_1d[5];
> +  int array_1d9[6];
> +  int array_2d[5][5];
> +  int array_2d9[6][6];
> +  int array_3d[5][5][5];
> +  int array_3d9[6][6][6];
> +  std::size_t i;
> +
> +  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
> +    *(array_1d + i) = 1;
> +  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
> +    *(array_1d9 + i) = i % 6 == 5 ? 9 : 1;
> +  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
> +    *(*array_2d + i) = 2;
> +  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
> +    *(*array_2d9 + i) = i / 6 == 5 || i % 6 == 5 ? 9 : 2;
> +  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
> +    *(**array_3d + i) = 3;
> +  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
> +    *(**array_3d9 + i) = i / 6 / 6 == 5 || i / 6 % 6 == 5 || i % 6 == 5 ? 9 : 3;
> +
> +  std::cout << "\n";					// Break here
> +  for (i = 0; i < sizeof (array_1d) / sizeof (int); i++)
> +    std::cout << " " << *(array_1d + i);
> +  std::cout << "\n";
> +  for (i = 0; i < sizeof (array_1d9) / sizeof (int); i++)
> +    std::cout << " " << *(array_1d9 + i);
> +  std::cout << "\n";
> +  for (i = 0; i < sizeof (array_2d) / sizeof (int); i++)
> +    std::cout << " " << *(*array_2d + i);
> +  std::cout << "\n";
> +  for (i = 0; i < sizeof (array_2d9) / sizeof (int); i++)
> +    std::cout << " " << *(*array_2d9 + i);
> +  std::cout << "\n";
> +  for (i = 0; i < sizeof (array_3d) / sizeof (int); i++)
> +    std::cout << " " << *(**array_3d + i);
> +  std::cout << "\n";
> +  for (i = 0; i < sizeof (array_3d9) / sizeof (int); i++)
> +    std::cout << " " << *(**array_3d9 + i);
> +  std::cout << "\n";
> +
> +  return 0;
> +}
> Index: src/gdb/testsuite/gdb.cp/array-repeat.exp
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.cp/array-repeat.exp
> @@ -0,0 +1,139 @@
> +# Copyright 2021 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/>.
> +
> +# Test the detection and printing of repeated elements in C++ arrays.
> +
> +if {[skip_cplus_tests]} { continue }
> +
> +standard_testfile .cc
> +
> +if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}]} {
> +    return -1
> +}
> +
> +if {![runto_main]} {
> +    perror "Could not run to main."
> +    continue
> +}
> +
> +gdb_breakpoint [gdb_get_line_number "Break here"]
> +gdb_continue_to_breakpoint "Break here"
> +
> +# Build up the expected output for each array.
> +set a9p9o "{9, 9, 9, 9, 9, 9}"
> +set a1p   "{1, 1, 1, 1, 1}"
> +set a1p9  "{1, 1, 1, 1, 1, 9}"
> +set a2po  "{2, 2, 2, 2, 2}"
> +set a2p   "{${a2po}, ${a2po}, ${a2po}, ${a2po}, ${a2po}}"
> +set a2p9o "{2, 2, 2, 2, 2, 9}"
> +set a2p9  "{${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a2p9o}, ${a9p9o}}"
> +set a3po  "{3, 3, 3, 3, 3}"
> +set a3p   "{${a3po}, ${a3po}, ${a3po}, ${a3po}, ${a3po}}"
> +set a3p   "{${a3p}, ${a3p}, ${a3p}, ${a3p}, ${a3p}}"
> +set a3p9o "{3, 3, 3, 3, 3, 9}"
> +set a3p9  "{${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a3p9o}, ${a9p9o}}"
> +set a9p9  "{${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}, ${a9p9o}}"
> +set a3p9  "{${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a3p9}, ${a9p9}}"
> +
> +# Convert the output into a regexp.
> +set r1p   [string_to_regexp $a1p]
> +set r1p9  [string_to_regexp $a1p9]
> +set r2po  [string_to_regexp $a2po]
> +set r2p9o [string_to_regexp $a2p9o]
> +set r2p   [string_to_regexp $a2p]
> +set r2p9  [string_to_regexp $a2p9]
> +set r3po  [string_to_regexp $a3po]
> +set r3p9o [string_to_regexp $a3p9o]
> +set r3p   [string_to_regexp $a3p]
> +set r3p9  [string_to_regexp $a3p9]
> +
> +set rep5  "<repeats 5 times>"
> +set rep6  "<repeats 6 times>"
> +
> +with_test_prefix "repeats=unlimited, elements=unlimited" {
> +    # Check the arrays print as expected.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d"  "${r1p}"
> +    gdb_test "print array_1d9" "${r1p9}"
> +    gdb_test "print array_2d"  "${r2p}"
> +    gdb_test "print array_2d9" "${r2p9}"
> +    gdb_test "print array_3d"  "${r3p}"
> +    gdb_test "print array_3d9" "${r3p9}"
> +}
> +
> +with_test_prefix "repeats=4, elements=unlimited" {
> +    # Now set the repeat limit.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{1 ${rep5}, 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
> +			    {{9 ${rep6}} ${rep6}}}"]
> +}
> +
> +with_test_prefix "repeats=unlimited, elements=3" {
> +    # Now set the element limit.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements 3"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{1, 1, 1...}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{1, 1, 1...}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{{2, 2, 2...}, {2, 2, 2...}, {2, 2, 2...}...}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{{{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...},\
> +			    {{3, 3, 3...}, {3, 3, 3...}, {3, 3, 3...}...}...}"]
> +}
> +
> +with_test_prefix "repeats=4, elements=12" {
> +    # Now set both limits.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements 12"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{1 ${rep5}, 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{{2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{{2 ${rep5}, 9} ${rep5}, {9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{{{3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{{{3 ${rep5}, 9} ${rep5}, {9 ${rep6}}} ${rep5},\
> +			    {{9 ${rep6}} ${rep6}}}"]
> +}
> 


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

* Re: [PATCH 5/6] Respect `set print array-indexes' with Fortran arrays
  2021-12-11 11:47 ` [PATCH 5/6] Respect `set print array-indexes' with Fortran arrays Maciej W. Rozycki
@ 2021-12-15 16:49   ` Andrew Burgess
  2022-01-08 16:27     ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Burgess @ 2021-12-15 16:49 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

* Maciej W. Rozycki <macro@embecosm.com> [2021-12-11 11:47:44 +0000]:

> Add `set print array-indexes' handling for Fortran arrays.  Currently 
> the setting is ignored and indices are never shown.
> 
> Keep track of the most recent index handled so that any outstanding 
> repeated elements printed when the limit set by `set print elements' is 
> hit have the correct index shown.
> 
> Output now looks like:
> 
> (gdb) set print array-indexes on
> (gdb) print array_1d
> $1 = ((-2) = 1, (-1) = 1, (0) = 1, (1) = 1, (2) = 1)
> (gdb) set print repeats 4
> (gdb) set print elements 12
> (gdb) print array_2d
> $2 = ((-2) = ((-2) = 2, <repeats 5 times>) (-1) = ((-2) = 2, <repeats 5 times>) (0) = ((-2) = 2, (-1) = 2, ...) ...)
> (gdb)
> 
> for a 5-element vector and a 5 by 5 array filled with the value of 2.
> ---
>  gdb/f-array-walker.h                        |   13 +
>  gdb/f-lang.c                                |   20 ++
>  gdb/f-lang.h                                |    6 
>  gdb/f-valprint.c                            |   40 ++++-
>  gdb/testsuite/gdb.fortran/array-indices.exp |  200 ++++++++++++++++++++++++++++
>  5 files changed, 266 insertions(+), 13 deletions(-)
> 
> gdb-fortran-set-print-array-indexes.diff
> Index: src/gdb/f-array-walker.h
> ===================================================================
> --- src.orig/gdb/f-array-walker.h
> +++ src/gdb/f-array-walker.h
> @@ -138,7 +138,8 @@ struct fortran_array_walker_base_impl
>       true only when this is the last element that will be processed in
>       this dimension.  */
>    void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
> -			  struct type *elt_type, LONGEST elt_off, bool last_p)
> +			  struct type *elt_type, LONGEST elt_off,
> +			  struct type *, LONGEST, bool last_p)

I'd like to see the new arguments given names, and the comment
extended to explain what they're for, given this is the base
implementation from which others inherit it seems like this is the
obvious place someone would look to figure this sort of thing out.

>    {
>      walk_1 (elt_type, elt_off, last_p);
>    }
> @@ -162,7 +163,8 @@ struct fortran_array_walker_base_impl
>           process_element (TYPE, OFFSET, true);
>         finish_dimension (true, true);
>       finish_dimension (false, true);  */
> -  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
> +  void process_element (struct type *elt_type, LONGEST elt_off,
> +			struct type *, LONGEST, bool last_p)

Again, I don't think it's GDB style to skip argument names - at least
it's not something I see often.

>    { /* Nothing.  */ }
>  };
>  
> @@ -223,6 +225,8 @@ class fortran_array_walker
>      if (m_nss != m_ndimensions)
>        {
>  	struct type *subarray_type = TYPE_TARGET_TYPE (check_typedef (type));
> +	gdb_assert (range_type->code () == TYPE_CODE_RANGE);

I think this assert should move up to immediately after we fetch
range_type, I'm pretty sure that if range_type isn't TYPE_CODE_RANGE
then the call to get_discrete_bounds will have already gone wrong.

> +	struct type *index_type = TYPE_TARGET_TYPE (range_type);
>  
>  	/* For dimensions other than the inner most, walk each element and
>  	   recurse while peeling off one more dimension of the array.  */
> @@ -239,7 +243,7 @@ class fortran_array_walker
>  		{
>  		  this->walk_1 (w_type, w_offset, w_last_p);
>  		},
> -	       subarray_type, new_offset, i == upperbound);
> +	       subarray_type, new_offset, index_type, i, i == upperbound);
>  	  }
>        }
>      else
> @@ -260,7 +264,8 @@ class fortran_array_walker
>  		elt_type = resolve_dynamic_type (elt_type, {}, e_address);
>  	      }
>  
> -	    m_impl.process_element (elt_type, elt_off, (i == upperbound));
> +	    m_impl.process_element (elt_type, elt_off, range_type, i,
> +				    i == upperbound);

This seems a little weird, you're passing the range_type through to
the index_type parameter?  Is this really what you mean?

Assuming you mean to pass TYPE_TARGET_TYPE(range_type) here, then the
index_type ends up being passed through to both process_element and
process_dimension.  You then end up placing the index_type into a
member variable within the m_impl.  I wonder if it would be better to
pass the index_type to start_dimension, and stash it there, then we'd
only need to pass the index value through maybe?  Or, maybe there
would be problems with handling multi-dimensional arrays?  I guess
it's pretty hard to actually uncover bugs in this area as the
index_type is almost always the same I think....

>  	  }
>        }
>  
> Index: src/gdb/f-lang.c
> ===================================================================
> --- src.orig/gdb/f-lang.c
> +++ src/gdb/f-lang.c
> @@ -330,7 +330,8 @@ class fortran_lazy_array_repacker_impl
>    /* Create a lazy value in target memory representing a single element,
>       then load the element into GDB's memory and copy the contents into the
>       destination value.  */
> -  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
> +  void process_element (struct type *elt_type, LONGEST elt_off,
> +			struct type *, LONGEST, bool last_p)

Missing arg names again here, and below.

Thanks,
Andrew


>    {
>      copy_element_to_dest (value_at_lazy (elt_type, m_addr + elt_off));
>    }
> @@ -368,7 +369,8 @@ class fortran_array_repacker_impl
>    /* Extract an element of ELT_TYPE at offset (M_BASE_OFFSET + ELT_OFF)
>       from the content buffer of M_VAL then copy this extracted value into
>       the repacked destination value.  */
> -  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
> +  void process_element (struct type *elt_type, LONGEST elt_off,
> +			struct type *, LONGEST, bool last_p)
>    {
>      struct value *elt
>        = value_from_component (m_val, elt_type, (elt_off + m_base_offset));
> @@ -1532,6 +1534,20 @@ fortran_structop_operation::evaluate (st
>  
>  /* See language.h.  */
>  
> +void
> +f_language::print_array_index (struct type *index_type, LONGEST index,
> +			       struct ui_file *stream,
> +			       const value_print_options *options) const
> +{
> +  struct value *index_value = value_from_longest (index_type, index);
> +
> +  fprintf_filtered (stream, "(");
> +  value_print (index_value, stream, options);
> +  fprintf_filtered (stream, ") = ");
> +}
> +
> +/* See language.h.  */
> +
>  void
>  f_language::language_arch_info (struct gdbarch *gdbarch,
>  				struct language_arch_info *lai) const
> Index: src/gdb/f-lang.h
> ===================================================================
> --- src.orig/gdb/f-lang.h
> +++ src/gdb/f-lang.h
> @@ -59,6 +59,12 @@ class f_language : public language_defn
>    }
>  
>    /* See language.h.  */
> +  void print_array_index (struct type *index_type,
> +			  LONGEST index,
> +			  struct ui_file *stream,
> +			  const value_print_options *options) const override;
> +
> +  /* See language.h.  */
>    void language_arch_info (struct gdbarch *gdbarch,
>  			   struct language_arch_info *lai) const override;
>  
> Index: src/gdb/f-valprint.c
> ===================================================================
> --- src.orig/gdb/f-valprint.c
> +++ src/gdb/f-valprint.c
> @@ -185,11 +185,14 @@ class fortran_array_printer_impl : publi
>    /* Called when processing dimensions of the array other than the
>       innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
>       the type of the element being extracted, and ELT_OFF is the offset
> -     of the element from the start of array being walked, and LAST_P is
> -     true only when this is the last element that will be processed in
> -     this dimension.  */
> +     of the element from the start of array being walked, INDEX_TYPE
> +     and INDEX is the type and the value respectively of the element's
> +     index in the dimension currently being walked and LAST_P is true
> +     only when this is the last element that will be processed in this
> +     dimension.  */
>    void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
> -			  struct type *elt_type, LONGEST elt_off, bool last_p)
> +			  struct type *elt_type, LONGEST elt_off,
> +			  struct type *index_type, LONGEST index, bool last_p)
>    {
>      size_t dim_indx = m_dimension - 1;
>      struct type *elt_type_prev = m_elt_type_prev;
> @@ -220,10 +223,15 @@ class fortran_array_printer_impl : publi
>  	    if (!repeated)
>  	      fputs_filtered (" ", m_stream);
>  	    m_elts += nrepeats * m_stats[dim_indx + 1].nelts;
> +	    m_index += nrepeats;
>  	  }
>  	else
>  	  for (LONGEST i = nrepeats; i > 0; i--)
> -	    walk_1 (elt_type_prev, elt_off_prev, repeated && i == 1);
> +	    {
> +	      maybe_print_array_index (index_type, index - nrepeats + repeated,
> +				       m_stream, m_options);
> +	      walk_1 (elt_type_prev, elt_off_prev, repeated && i == 1);
> +	    }
>  
>  	if (!repeated)
>  	  {
> @@ -234,6 +242,8 @@ class fortran_array_printer_impl : publi
>  	       to `continue_walking' from our caller won't do that.  */
>  	    if (m_elts < m_options->print_max)
>  	      {
> +		maybe_print_array_index (index_type, index,
> +					 m_stream, m_options);
>  		walk_1 (elt_type, elt_off, last_p);
>  		nrepeats++;
>  	      }
> @@ -247,14 +257,20 @@ class fortran_array_printer_impl : publi
>  
>      m_elt_type_prev = elt_type;
>      m_elt_off_prev = elt_off;
> +    m_index_type = index_type;
> +    m_index = index;
>  
>      if (last_p)
>        m_stats[dim_indx].elts_counted = true;
>    }
>  
>    /* Called to process an element of ELT_TYPE at offset ELT_OFF from the
> -     start of the parent object.  */
> -  void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
> +     start of the parent object, where INDEX_TYPE and INDEX is the type
> +     and the value respectively of the element's index in the dimension
> +     currently being walked and LAST_P is true only when this is the last
> +     element that will be processed in this dimension.  */
> +  void process_element (struct type *elt_type, LONGEST elt_off,
> +			struct type *index_type, LONGEST index, bool last_p)
>    {
>      size_t dim_indx = m_dimension - 1;
>      struct type *elt_type_prev = m_elt_type_prev;
> @@ -284,6 +300,7 @@ class fortran_array_printer_impl : publi
>  
>  	    if (printed)
>  	      fputs_filtered (", ", m_stream);
> +	    maybe_print_array_index (index_type, index, m_stream, m_options);
>  	    common_val_print (e_val, m_stream, m_recurse, m_options,
>  			      current_language);
>  	  }
> @@ -293,6 +310,8 @@ class fortran_array_printer_impl : publi
>  
>      m_elt_type_prev = elt_type;
>      m_elt_off_prev = elt_off;
> +    m_index_type = index_type;
> +    m_index = index;
>      ++m_elts;
>  
>      if (last_p && !m_stats[dim_indx].elts_counted)
> @@ -318,6 +337,7 @@ class fortran_array_printer_impl : publi
>  			  plongest (nrepeats + 1),
>  			  nullptr);
>  	annotate_elt_rep_end ();
> +	m_index += nrepeats;
>        }
>      else
>        {
> @@ -326,6 +346,8 @@ class fortran_array_printer_impl : publi
>  
>  	for (LONGEST i = nrepeats; i > 0; i--)
>  	  {
> +	    maybe_print_array_index (m_index_type, m_index - i + 1,
> +				     m_stream, m_options);
>  	    common_val_print (e_val, m_stream, m_recurse, m_options,
>  			      current_language);
>  	    if (i > 1)
> @@ -398,6 +420,10 @@ class fortran_array_printer_impl : publi
>    struct type *m_elt_type_prev;
>    LONGEST m_elt_off_prev;
>  
> +  /* Index type and value tracker.  */
> +  struct type *m_index_type;
> +  LONGEST m_index;
> +
>    /* Per-dimension stats.  */
>    std::vector<struct dimension_stats> m_stats;
>  };
> Index: src/gdb/testsuite/gdb.fortran/array-indices.exp
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.fortran/array-indices.exp
> @@ -0,0 +1,200 @@
> +# Copyright 2021 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/>.
> +
> +# Test the printing of element indices in Fortran arrays.
> +
> +if {[skip_fortran_tests]} { return -1 }
> +
> +load_lib fortran.exp
> +
> +# Build up the expected output for each array.
> +set n0    {(-2)}
> +set n1    {(-1)}
> +set n2    {(0)}
> +set n3    {(1)}
> +set n4    {(2)}
> +set n5    {(3)}
> +set a9p9o "($n0 = 9, $n1 = 9, $n2 = 9, $n3 = 9, $n4 = 9, $n5 = 9)"
> +set a1p   "($n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1)"
> +set a1p9  "($n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1, $n5 = 9)"
> +set a2po  "($n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2)"
> +set a2p   "($n0 = ${a2po} $n1 = ${a2po} $n2 = ${a2po} $n3 = ${a2po}\
> +	    $n4 = ${a2po})"
> +set a2p9o "($n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2, $n5 = 9)"
> +set a2p9  "($n0 = ${a2p9o} $n1 = ${a2p9o} $n2 = ${a2p9o} $n3 = ${a2p9o}\
> +	    $n4 = ${a2p9o} $n5 = ${a9p9o})"
> +set a3po  "($n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3)"
> +set a3p   "($n0 = ${a3po} $n1 = ${a3po} $n2 = ${a3po} $n3 = ${a3po}\
> +	    $n4 = ${a3po})"
> +set a3p   "($n0 = ${a3p} $n1 = ${a3p} $n2 = ${a3p} $n3 = ${a3p} $n4 = ${a3p})"
> +set a3p9o "($n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3, $n5 = 9)"
> +set a3p9  "($n0 = ${a3p9o} $n1 = ${a3p9o} $n2 = ${a3p9o} $n3 = ${a3p9o}\
> +	    $n4 = ${a3p9o} $n5 = ${a9p9o})"
> +set a9p9  "($n0 = ${a9p9o} $n1 = ${a9p9o} $n2 = ${a9p9o} $n3 = ${a9p9o}\
> +	    $n4 = ${a9p9o} $n5 = ${a9p9o})"
> +set a3p9  "($n0 = ${a3p9} $n1 = ${a3p9} $n2 = ${a3p9} $n3 = ${a3p9}\
> +	    $n4 = ${a3p9} $n5 = ${a9p9})"
> +
> +# Convert the output into a regexp.
> +set r1p   [string_to_regexp $a1p]
> +set r1p9  [string_to_regexp $a1p9]
> +set r2po  [string_to_regexp $a2po]
> +set r2p9o [string_to_regexp $a2p9o]
> +set r2p   [string_to_regexp $a2p]
> +set r2p9  [string_to_regexp $a2p9]
> +set r3po  [string_to_regexp $a3po]
> +set r3p9o [string_to_regexp $a3p9o]
> +set r3p   [string_to_regexp $a3p]
> +set r3p9  [string_to_regexp $a3p9]
> +
> +set rep5  "<repeats 5 times>"
> +set rep6  "<repeats 6 times>"
> +
> +proc array_repeat { variant } {
> +    global testfile srcfile
> +    upvar n0 n0 n1 n1 n2 n2 n5 n5
> +    upvar r1p r1p r1p9 r1p9 r2po r2po r2p9o r2p9o r2p r2p r2p9 r2p9
> +    upvar r3po r3po r3p9o r3p9o r3p r3p r3p9 r3p9
> +    upvar a2po a2po a2p9o a2p9o a3po a3po a3p9o a3p9o
> +    upvar rep5 rep5 rep6 rep6
> +
> +    standard_testfile "${variant}.f90"
> +
> +    if {[prepare_for_testing ${testfile}.exp ${variant} ${srcfile} \
> +	    {debug f90}]} {
> +	return -1
> +    }
> +
> +    with_test_prefix "${variant}" {
> +	gdb_test_no_output "set print array-indexes on"
> +    }
> +
> +    if {![fortran_runto_main]} {
> +	perror "Could not run to main."
> +	continue
> +    }
> +
> +    gdb_breakpoint [gdb_get_line_number "Break here"]
> +    gdb_continue_to_breakpoint "${variant}"
> +
> +    with_test_prefix "${variant}: repeats=unlimited, elements=unlimited" {
> +	# Check the arrays print as expected.
> +	gdb_test_no_output "set print repeats unlimited"
> +	gdb_test_no_output "set print elements unlimited"
> +
> +	gdb_test "print array_1d"  "${r1p}"
> +	gdb_test "print array_1d9" "${r1p9}"
> +	gdb_test "print array_2d"  "${r2p}"
> +	gdb_test "print array_2d9" "${r2p9}"
> +	gdb_test "print array_3d"  "${r3p}"
> +	gdb_test "print array_3d9" "${r3p9}"
> +    }
> +
> +    with_test_prefix "${variant}: repeats=4, elements=unlimited" {
> +	# Now set the repeat limit.
> +	gdb_test_no_output "set print repeats 4"
> +	gdb_test_no_output "set print elements unlimited"
> +
> +	gdb_test "print array_1d" \
> +	    [string_to_regexp "($n0 = 1, ${rep5})"]
> +	gdb_test "print array_1d9" \
> +	    [string_to_regexp "($n0 = 1, ${rep5}, $n5 = 9)"]
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}) ${rep5})"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}, $n5 = 9) ${rep5}\
> +				$n5 = ($n0 = 9, ${rep6}))"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}) ${rep5})\
> +				${rep5})"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}, $n5 = 9)\
> +				       ${rep5} $n5 = ($n0 = 9, ${rep6}))\
> +				${rep5}\
> +				$n5 = ($n0 = ($n0 = 9, ${rep6}) ${rep6}))"]
> +    }
> +
> +    with_test_prefix "${variant}: repeats=unlimited, elements=12" {
> +	# Now set the element limit.
> +	gdb_test_no_output "set print repeats unlimited"
> +	gdb_test_no_output "set print elements 12"
> +
> +	gdb_test "print array_1d"  "${r1p}"
> +	gdb_test "print array_1d9" "${r1p9}"
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "($n0 = ${a2po} $n1 = ${a2po}\
> +				$n2 = ($n0 = 2, $n1 = 2, ...) ...)"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "($n0 = ${a2p9o} $n1 = ${a2p9o} ...)"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "($n0 = ($n0 = ${a3po} $n1 = ${a3po}\
> +				       $n2 = ($n0 = 3, $n1 = 3, ...)\
> +				       ...) ...)"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "($n0 = ($n0 = ${a3p9o} $n1 = ${a3p9o} ...)\
> +				...)"]
> +    }
> +
> +    with_test_prefix "${variant}: repeats=4, elements=12" {
> +	# Now set both limits.
> +	gdb_test_no_output "set print repeats 4"
> +	gdb_test_no_output "set print elements 12"
> +
> +	gdb_test "print array_1d" \
> +	    [string_to_regexp "($n0 = 1, ${rep5})"]
> +	gdb_test "print array_1d9" \
> +	    [string_to_regexp "($n0 = 1, ${rep5}, $n5 = 9)"]
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5})\
> +				$n1 = ($n0 = 2, ${rep5})\
> +				$n2 = ($n0 = 2, $n1 = 2, ...) ...)"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}, $n5 = 9)\
> +				$n1 = ($n0 = 2, ${rep5}, $n5 = 9) ...)"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5})\
> +				       $n1 = ($n0 = 3, ${rep5})\
> +				       $n2 = ($n0 = 3, $n1 = 3, ...) ...) ...)"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}, $n5 = 9)\
> +				       $n1 = ($n0 = 3, ${rep5}, $n5 = 9)\
> +				       ...) ...)"]
> +    }
> +
> +    with_test_prefix "${variant}: repeats=4, elements=30" {
> +	# Now set both limits.
> +	gdb_test_no_output "set print repeats 4"
> +	gdb_test_no_output "set print elements 30"
> +
> +	gdb_test "print array_1d" \
> +	    [string_to_regexp "($n0 = 1, ${rep5})"]
> +	gdb_test "print array_1d9" \
> +	    [string_to_regexp "($n0 = 1, ${rep5}, $n5 = 9)"]
> +	gdb_test "print array_2d" \
> +	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}) ${rep5})"]
> +	gdb_test "print array_2d9" \
> +	    [string_to_regexp "($n0 = ($n0 = 2, ${rep5}, $n5 = 9) ${rep5}\
> +				...)"]
> +	gdb_test "print array_3d" \
> +	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}) ${rep5})\
> +				$n1 = ($n0 = ($n0 = 3, ${rep5}) ...) ...)"]
> +	gdb_test "print array_3d9" \
> +	    [string_to_regexp "($n0 = ($n0 = ($n0 = 3, ${rep5}, $n5 = 9)\
> +				       ${rep5} ...) ...)"]
> +    }
> +}
> +
> +array_repeat "array-repeat"
> +array_repeat "array-slices-repeat"
> 


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

* Re: [PATCH 6/6] Add `set print array-indexes' tests for C/C++ arrays
  2021-12-11 11:48 ` [PATCH 6/6] Add `set print array-indexes' tests for C/C++ arrays Maciej W. Rozycki
@ 2021-12-15 16:51   ` Andrew Burgess
  2022-01-08 16:27     ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Burgess @ 2021-12-15 16:51 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

* Maciej W. Rozycki <macro@embecosm.com> [2021-12-11 11:48:01 +0000]:

> Add `set print array-indexes' tests for C/C++ arrays, complementing one 
> for Fortran arrays.
> ---
>  gdb/testsuite/gdb.base/array-indices.exp |  174 ++++++++++++++++++++++++++++++
>  gdb/testsuite/gdb.cp/array-indices.exp   |  176 +++++++++++++++++++++++++++++++

If the previous C/C++ tests are combined then these would naturally be
combined too.  Otherwise LGTM.

Thanks,
Andrew

>  2 files changed, 350 insertions(+)
> 
> gdb-set-print-array-indexes-test.diff
> Index: src/gdb/testsuite/gdb.base/array-indices.exp
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.base/array-indices.exp
> @@ -0,0 +1,174 @@
> +# Copyright 2021 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/>.
> +
> +# Test the printing of element indices in C arrays.
> +
> +standard_testfile array-repeat.c
> +
> +if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug}]} {
> +    return -1
> +}
> +
> +gdb_test_no_output "set print array-indexes on"
> +
> +if {![runto_main]} {
> +    perror "Could not run to main."
> +    continue
> +}
> +
> +gdb_breakpoint [gdb_get_line_number "Break here"]
> +gdb_continue_to_breakpoint "Break here"
> +
> +# Build up the expected output for each array.
> +set n0    {[0]}
> +set n1    {[1]}
> +set n2    {[2]}
> +set n3    {[3]}
> +set n4    {[4]}
> +set n5    {[5]}
> +set a9p9o "{$n0 = 9, $n1 = 9, $n2 = 9, $n3 = 9, $n4 = 9, $n5 = 9}"
> +set a1p   "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1}"
> +set a1p9  "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1, $n5 = 9}"
> +set a2po  "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2}"
> +set a2p   "{$n0 = ${a2po}, $n1 = ${a2po}, $n2 = ${a2po}, $n3 = ${a2po},\
> +	    $n4 = ${a2po}}"
> +set a2p9o "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2, $n5 = 9}"
> +set a2p9  "{$n0 = ${a2p9o}, $n1 = ${a2p9o}, $n2 = ${a2p9o}, $n3 = ${a2p9o},\
> +	    $n4 = ${a2p9o}, $n5 = ${a9p9o}}"
> +set a3po  "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3}"
> +set a3p   "{$n0 = ${a3po}, $n1 = ${a3po}, $n2 = ${a3po}, $n3 = ${a3po},\
> +	    $n4 = ${a3po}}"
> +set a3p   "{$n0 = ${a3p}, $n1 = ${a3p}, $n2 = ${a3p}, $n3 = ${a3p},\
> +	    $n4 = ${a3p}}"
> +set a3p9o "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3, $n5 = 9}"
> +set a3p9  "{$n0 = ${a3p9o}, $n1 = ${a3p9o}, $n2 = ${a3p9o}, $n3 = ${a3p9o},\
> +	    $n4 = ${a3p9o}, $n5 = ${a9p9o}}"
> +set a9p9  "{$n0 = ${a9p9o}, $n1 = ${a9p9o}, $n2 = ${a9p9o}, $n3 = ${a9p9o},\
> +	    $n4 = ${a9p9o}, $n5 = ${a9p9o}}"
> +set a3p9  "{$n0 = ${a3p9}, $n1 = ${a3p9}, $n2 = ${a3p9}, $n3 = ${a3p9},\
> +	    $n4 = ${a3p9}, $n5 = ${a9p9}}"
> +
> +# Convert the output into a regexp.
> +set r1p   [string_to_regexp $a1p]
> +set r1p9  [string_to_regexp $a1p9]
> +set r2po  [string_to_regexp $a2po]
> +set r2p9o [string_to_regexp $a2p9o]
> +set r2p   [string_to_regexp $a2p]
> +set r2p9  [string_to_regexp $a2p9]
> +set r3po  [string_to_regexp $a3po]
> +set r3p9o [string_to_regexp $a3p9o]
> +set r3p   [string_to_regexp $a3p]
> +set r3p9  [string_to_regexp $a3p9]
> +
> +set rep5  "<repeats 5 times>"
> +set rep6  "<repeats 6 times>"
> +
> +with_test_prefix "repeats=unlimited, elements=unlimited" {
> +    # Check the arrays print as expected.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d"  "${r1p}"
> +    gdb_test "print array_1d9" "${r1p9}"
> +    gdb_test "print array_2d"  "${r2p}"
> +    gdb_test "print array_2d9" "${r2p9}"
> +    gdb_test "print array_3d"  "${r3p}"
> +    gdb_test "print array_3d9" "${r3p9}"
> +}
> +
> +with_test_prefix "repeats=4, elements=unlimited" {
> +    # Now set the repeat limit.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
> +			    $n5 = {$n0 = 9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
> +				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
> +			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
> +}
> +
> +with_test_prefix "repeats=unlimited, elements=3" {
> +    # Now set the element limit.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements 3"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3,\
> +					  $n2 = 3...}...}...}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3,\
> +					  $n2 = 3...}...}...}"]
> +}
> +
> +with_test_prefix "repeats=4, elements=12" {
> +    # Now set both limits.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements 12"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
> +			    $n5 = {$n0 = 9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
> +				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
> +			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
> +}
> Index: src/gdb/testsuite/gdb.cp/array-indices.exp
> ===================================================================
> --- /dev/null
> +++ src/gdb/testsuite/gdb.cp/array-indices.exp
> @@ -0,0 +1,176 @@
> +# Copyright 2021 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/>.
> +
> +# Test the printing of element indices in C++ arrays.
> +
> +if {[skip_cplus_tests]} { continue }
> +
> +standard_testfile array-repeat.cc
> +
> +if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}]} {
> +    return -1
> +}
> +
> +gdb_test_no_output "set print array-indexes on"
> +
> +if {![runto_main]} {
> +    perror "Could not run to main."
> +    continue
> +}
> +
> +gdb_breakpoint [gdb_get_line_number "Break here"]
> +gdb_continue_to_breakpoint "Break here"
> +
> +# Build up the expected output for each array.
> +set n0    {[0]}
> +set n1    {[1]}
> +set n2    {[2]}
> +set n3    {[3]}
> +set n4    {[4]}
> +set n5    {[5]}
> +set a9p9o "{$n0 = 9, $n1 = 9, $n2 = 9, $n3 = 9, $n4 = 9, $n5 = 9}"
> +set a1p   "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1}"
> +set a1p9  "{$n0 = 1, $n1 = 1, $n2 = 1, $n3 = 1, $n4 = 1, $n5 = 9}"
> +set a2po  "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2}"
> +set a2p   "{$n0 = ${a2po}, $n1 = ${a2po}, $n2 = ${a2po}, $n3 = ${a2po},\
> +	    $n4 = ${a2po}}"
> +set a2p9o "{$n0 = 2, $n1 = 2, $n2 = 2, $n3 = 2, $n4 = 2, $n5 = 9}"
> +set a2p9  "{$n0 = ${a2p9o}, $n1 = ${a2p9o}, $n2 = ${a2p9o}, $n3 = ${a2p9o},\
> +	    $n4 = ${a2p9o}, $n5 = ${a9p9o}}"
> +set a3po  "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3}"
> +set a3p   "{$n0 = ${a3po}, $n1 = ${a3po}, $n2 = ${a3po}, $n3 = ${a3po},\
> +	    $n4 = ${a3po}}"
> +set a3p   "{$n0 = ${a3p}, $n1 = ${a3p}, $n2 = ${a3p}, $n3 = ${a3p},\
> +	    $n4 = ${a3p}}"
> +set a3p9o "{$n0 = 3, $n1 = 3, $n2 = 3, $n3 = 3, $n4 = 3, $n5 = 9}"
> +set a3p9  "{$n0 = ${a3p9o}, $n1 = ${a3p9o}, $n2 = ${a3p9o}, $n3 = ${a3p9o},\
> +	    $n4 = ${a3p9o}, $n5 = ${a9p9o}}"
> +set a9p9  "{$n0 = ${a9p9o}, $n1 = ${a9p9o}, $n2 = ${a9p9o}, $n3 = ${a9p9o},\
> +	    $n4 = ${a9p9o}, $n5 = ${a9p9o}}"
> +set a3p9  "{$n0 = ${a3p9}, $n1 = ${a3p9}, $n2 = ${a3p9}, $n3 = ${a3p9},\
> +	    $n4 = ${a3p9}, $n5 = ${a9p9}}"
> +
> +# Convert the output into a regexp.
> +set r1p   [string_to_regexp $a1p]
> +set r1p9  [string_to_regexp $a1p9]
> +set r2po  [string_to_regexp $a2po]
> +set r2p9o [string_to_regexp $a2p9o]
> +set r2p   [string_to_regexp $a2p]
> +set r2p9  [string_to_regexp $a2p9]
> +set r3po  [string_to_regexp $a3po]
> +set r3p9o [string_to_regexp $a3p9o]
> +set r3p   [string_to_regexp $a3p]
> +set r3p9  [string_to_regexp $a3p9]
> +
> +set rep5  "<repeats 5 times>"
> +set rep6  "<repeats 6 times>"
> +
> +with_test_prefix "repeats=unlimited, elements=unlimited" {
> +    # Check the arrays print as expected.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d"  "${r1p}"
> +    gdb_test "print array_1d9" "${r1p9}"
> +    gdb_test "print array_2d"  "${r2p}"
> +    gdb_test "print array_2d9" "${r2p9}"
> +    gdb_test "print array_3d"  "${r3p}"
> +    gdb_test "print array_3d9" "${r3p9}"
> +}
> +
> +with_test_prefix "repeats=4, elements=unlimited" {
> +    # Now set the repeat limit.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements unlimited"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
> +			    $n5 = {$n0 = 9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
> +				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
> +			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
> +}
> +
> +with_test_prefix "repeats=unlimited, elements=3" {
> +    # Now set the element limit.
> +    gdb_test_no_output "set print repeats unlimited"
> +    gdb_test_no_output "set print elements 3"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{$n0 = 1, $n1 = 1, $n2 = 1...}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{$n0 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n1 = {$n0 = 2, $n1 = 2, $n2 = 2...},\
> +			    $n2 = {$n0 = 2, $n1 = 2, $n2 = 2...}...}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3,\
> +					  $n2 = 3...}...}...}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n1 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3, $n2 = 3...}...},\
> +			    $n2 = {$n0 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n1 = {$n0 = 3, $n1 = 3, $n2 = 3...},\
> +				   $n2 = {$n0 = 3, $n1 = 3,\
> +					  $n2 = 3...}...}...}"]
> +}
> +
> +with_test_prefix "repeats=4, elements=12" {
> +    # Now set both limits.
> +    gdb_test_no_output "set print repeats 4"
> +    gdb_test_no_output "set print elements 12"
> +
> +    gdb_test "print array_1d" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}}"]
> +    gdb_test "print array_1d9" \
> +	[string_to_regexp "{$n0 = 1 ${rep5}, $n5 = 9}"]
> +    gdb_test "print array_2d" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}} ${rep5}}"]
> +    gdb_test "print array_2d9" \
> +	[string_to_regexp "{$n0 = {$n0 = 2 ${rep5}, $n5 = 9} ${rep5},\
> +			    $n5 = {$n0 = 9 ${rep6}}}"]
> +    gdb_test "print array_3d" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}} ${rep5}} ${rep5}}"]
> +    gdb_test "print array_3d9" \
> +	[string_to_regexp "{$n0 = {$n0 = {$n0 = 3 ${rep5}, $n5 = 9} ${rep5},\
> +				   $n5 = {$n0 = 9 ${rep6}}} ${rep5},\
> +			    $n5 = {$n0 = {$n0 = 9 ${rep6}} ${rep6}}}"]
> +}
> 


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

* Re: [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list
  2021-12-15 13:18   ` Andrew Burgess
@ 2021-12-17 15:03     ` Maciej W. Rozycki
  0 siblings, 0 replies; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-17 15:03 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On Wed, 15 Dec 2021, Andrew Burgess wrote:

> > Following our coding convention initialize the `m_ndimensions' member in 
> > the member initializer list rather than in the body of the constructor 
> > of the `fortran_array_walker' class.  No functional change.
> > ---
> >  gdb/f-array-walker.h |    7 +++----
> >  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> LGTM.

 Applied now, thanks for your review.

  Maciej

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

* Re: [PATCH 2/6] Avoid redundant operations in `fortran_array_walker'
  2021-12-15 13:19   ` Andrew Burgess
@ 2021-12-17 15:04     ` Maciej W. Rozycki
  0 siblings, 0 replies; 19+ messages in thread
From: Maciej W. Rozycki @ 2021-12-17 15:04 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On Wed, 15 Dec 2021, Andrew Burgess wrote:

> > Move inner dimension's element type determination outside the respective 
> > loops in `fortran_array_walker'.  The operation is exactly the same with 
> > each iteration, so there is no point in redoing it for each element and 
> > while a smart compiler might be able to move it outside the loop it is 
> > regardless a bad coding style.  No functional change.
> 
> LGTM.

 Thank you for your review.  I have committed this change now.

  Maciej

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

* Re: [PATCH 3/6] Respect `set print repeats' with Fortran arrays
  2021-12-15 15:18   ` Andrew Burgess
@ 2022-01-08 16:25     ` Maciej W. Rozycki
  0 siblings, 0 replies; 19+ messages in thread
From: Maciej W. Rozycki @ 2022-01-08 16:25 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On Wed, 15 Dec 2021, Andrew Burgess wrote:

> > Index: src/gdb/f-array-walker.h
> > ===================================================================
> > --- src.orig/gdb/f-array-walker.h
> > +++ src/gdb/f-array-walker.h
> > @@ -131,6 +131,18 @@ struct fortran_array_walker_base_impl
> >    void finish_dimension (bool inner_p, bool last_p)
> >    { /* Nothing.  */ }
> >  
> > +  /* Called when processing dimensions of the array other than the
> > +     innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
> > +     the type of the element being extracted, and ELT_OFF is the offset
> > +     of the element from the start of array being walked, and LAST_P is
> > +     true only when this is the last element that will be processed in
> > +     this dimension.  */
> > +  void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
> 
> I think you should be using gdb::function_view here as the lambda only
> needs to live for the lifetime of the function call.

 Changed; I wasn't aware of `gdb::function_view'.

> > Index: src/gdb/f-valprint.c
> > ===================================================================
> > --- src.orig/gdb/f-valprint.c
> > +++ src/gdb/f-valprint.c
> > @@ -21,6 +21,7 @@
> >     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> >  
> >  #include "defs.h"
> > +#include "annotate.h"
> >  #include "symtab.h"
> >  #include "gdbtypes.h"
> >  #include "expression.h"
> > @@ -96,6 +97,15 @@ f77_get_dynamic_length_of_aggregate (str
> >      * TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type)));
> >  }
> >  
> > +/* Per-dimension statistics.  */
> > +
> > +struct dimension_stats
> > +{
> > +  /* Element counter.  */
> > +  int nelts;
> > +  bool elts_counted;
> > +};
> 
> The comments here seem to just be repeating the variable names.  Could
> we give more information.  e.g. "Element counter", what elements is it
> counting, it's per dimension, but, is it counting every element?  The
> number of repeated elements in a series?  What does the bool mean?
> Does it mean we've counted everything?  Just started counting?

 It counts the total number of elements in each dimension; obviously this 
needs to be done only once per dimension.

 Your discussion about `index_type' with 5/6 has actually inspired me to 
get rid of this active counter however and pass the total per-dimension 
element count as a parameter to `start_dimension' instead.  I think it 
simplifies code enough to make it worth it.

> I also wondered about whether we could replace this with, or otherwise
> make use of a gdb::optional here?  I see there's one place where we
> set elts_counted without appearing to set nelts, I'm guessing we're
> picking up the default value of 0 in that case?

 It's not clear to me what you mean with using `gdb::optional' here and we 
actually do always set `nelts' before flipping `elts_counted'.  If you 
think of code in `process_dimension', then we have:

    if (!repeated || last_p)
      {
	/* ... */
	if (!m_stats[dim_indx].elts_counted)
	  m_stats[dim_indx].nelts += nrepeats * m_stats[dim_indx + 1].nelts;
      }
    /* ... */
    if (last_p)
      m_stats[dim_indx].elts_counted = true;

there, so `nelts' does get set as both conditionals execute if `last_p', 
which is when we're at the last element that concludes counting.  It's now 
gone along with the active counter though.

> > @@ -128,8 +141,18 @@ class fortran_array_printer_impl : publi
> >    bool continue_walking (bool should_continue)
> >    {
> >      bool cont = should_continue && (m_elts < m_options->print_max);
> > +
> >      if (!cont && should_continue)
> > -      fputs_filtered ("...", m_stream);
> > +      {
> > +	if (m_nrepeats)
> 
> The GDB style is to not treat integers as booleans, so this should be
> written as:
> 
>   if (m_nrepeats > 0)

 I think the rule either changed or was only introduced at one point and I 
missed that.  Fixed now, though I chose to transcribe it literally.

> > @@ -149,22 +178,200 @@ class fortran_array_printer_impl : publi
> >      fputs_filtered (")", m_stream);
> >      if (!last_p)
> >        fputs_filtered (" ", m_stream);
> > +
> > +    m_dimension--;
> > +  }
> > +
> > +  /* Called when processing dimensions of the array other than the
> > +     innermost one.  WALK_1 is the walker to normally call, ELT_TYPE is
> > +     the type of the element being extracted, and ELT_OFF is the offset
> > +     of the element from the start of array being walked, and LAST_P is
> > +     true only when this is the last element that will be processed in
> > +     this dimension.  */
> > +  void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
> > +			  struct type *elt_type, LONGEST elt_off, bool last_p)
> > +  {
> > +    size_t dim_indx = m_dimension - 1;
> > +    struct type *elt_type_prev = m_elt_type_prev;
> > +    LONGEST elt_off_prev = m_elt_off_prev;
> > +    bool repeated = (m_options->repeat_count_threshold < UINT_MAX
> > +		     && elt_type_prev != nullptr
> > +		     && (m_elts + ((m_nrepeats + 1)
> > +				   * m_stats[dim_indx + 1].nelts)
> > +			 <= m_options->print_max)
> > +		     && dimension_contents_eq (m_val, elt_type,
> > +					       elt_off_prev, elt_off));
> > +
> > +    if (repeated)
> > +      m_nrepeats++;
> > +    if (!repeated || last_p)
> > +      {
> > +	LONGEST nrepeats = m_nrepeats;
> > +
> > +	m_nrepeats = 0;
> > +	if (nrepeats >= m_options->repeat_count_threshold)
> > +	  {
> > +	    annotate_elt_rep (nrepeats + 1);
> > +	    fprintf_filtered (m_stream, "%p[<repeats %s times>%p]",
> > +			      metadata_style.style ().ptr (),
> > +			      plongest (nrepeats + 1),
> > +			      nullptr);
> > +	    annotate_elt_rep_end ();
> > +	    if (!repeated)
> > +	      fputs_filtered (" ", m_stream);
> > +	    m_elts += nrepeats * m_stats[dim_indx + 1].nelts;
> > +	  }
> > +	else
> > +	  for (LONGEST i = nrepeats; i > 0; i--)
> > +	    walk_1 (elt_type_prev, elt_off_prev, repeated && i == 1);
> > +
> > +	if (!repeated)
> > +	  {
> > +	    /* We need to specially handle the case of hitting `print_max'
> > +	       exactly as recursing would cause lone `(...)' to be printed.
> > +	       And we need to print `...' by hand if the skipped element
> > +	       would be the last one processed, because the subsequent call
> > +	       to `continue_walking' from our caller won't do that.  */
> > +	    if (m_elts < m_options->print_max)
> > +	      {
> > +		walk_1 (elt_type, elt_off, last_p);
> > +		nrepeats++;
> > +	      }
> > +	    else if (last_p)
> > +	      fputs_filtered ("...", m_stream);
> > +	  }
> > +
> > +	if (!m_stats[dim_indx].elts_counted)
> > +	  m_stats[dim_indx].nelts += nrepeats * m_stats[dim_indx + 1].nelts;
> > +      }
> > +
> > +    m_elt_type_prev = elt_type;
> > +    m_elt_off_prev = elt_off;
> > +
> > +    if (last_p)
> > +      m_stats[dim_indx].elts_counted = true;
> >    }
> >  
> >    /* Called to process an element of ELT_TYPE at offset ELT_OFF from the
> >       start of the parent object.  */
> >    void process_element (struct type *elt_type, LONGEST elt_off, bool last_p)
> >    {
> > -    /* Extract the element value from the parent value.  */
> > -    struct value *e_val
> > -      = value_from_component (m_val, elt_type, elt_off);
> > -    common_val_print (e_val, m_stream, m_recurse, m_options, current_language);
> > -    if (!last_p)
> > -      fputs_filtered (", ", m_stream);
> > +    size_t dim_indx = m_dimension - 1;
> > +    struct type *elt_type_prev = m_elt_type_prev;
> > +    LONGEST elt_off_prev = m_elt_off_prev;
> > +    bool repeated = (m_options->repeat_count_threshold < UINT_MAX
> > +		     && elt_type_prev != nullptr
> > +		     && value_contents_eq (m_val, elt_off_prev, m_val, elt_off,
> > +					   TYPE_LENGTH (elt_type)));
> > +
> > +    if (repeated)
> > +      m_nrepeats++;
> > +    if (!repeated || last_p)
> > +      {
> > +	bool printed = false;
> 
> I noticed that `printed` isn't actually needed, as we could say:
> 
>   bool printed = m_nrepeats;
> 
> so you could just use m_nrepeats instead.

 Umm, no, because `process_outstanding_elements' clears `m_nrepeats' so we 
need to cache the state before the call.  And then how we set `printed' it 
is a matter of style (I think it's clearer to the reader the way I chose 
as `printed = m_nrepeats' would really be a conditional in disguise; and 
it would have to be `printed = m_nrepeats != 0' to match our requirement 
not to use integers as booleans).

 Further inspired by the removal of the active element counter I have 
decided to remove the `process_outstanding_elements' as well.  In case it 
wasn't obvious from code (or descriptions) it was only ever executed at 
the innermost dimension, having been factored out from an earlier version 
to avoid duplication.

 This, and especially the hairy handling of `m_index' needed to be added 
with 5/6, kept bothering me, so I chose to remove the call made from 
`continue_walking' (which the hairy handling was required for) and check 
for `print_max' explicitly in `process_element' similarly to how it's been 
handled in `process_dimension'.  This way all the outstanding element 
processing needed where `print_max' is hit is done in a single place, 
simplifying code further.

 So the call to `process_outstanding_elements' has gone now, but I chose 
to keep the code mostly as is even though there's now a local `nrepeats' 
variable, because I still think the intent of this code should be clearer 
to the reader this way.  There are enough corner cases already to make 
this piece complicated enough regardless.

> > +
> > +	if (m_nrepeats)
> 
> Missing '> 0' again.

 Fixed.

> > +	  {
> > +	    process_outstanding_elements (elt_type, elt_off_prev);
> > +	    printed = true;
> > +	  }
> > +
> > +	if (!repeated)
> > +	  {
> > +	    /* Extract the element value from the parent value.  */
> > +	    struct value *e_val
> > +	      = value_from_component (m_val, elt_type, elt_off);
> > +
> > +	    if (printed)
> > +	      fputs_filtered (", ", m_stream);
> > +	    common_val_print (e_val, m_stream, m_recurse, m_options,
> > +			      current_language);
> > +	  }
> > +	if (!last_p)
> > +	  fputs_filtered (", ", m_stream);
> > +      }
> > +
> > +    m_elt_type_prev = elt_type;
> > +    m_elt_off_prev = elt_off;
> >      ++m_elts;
> > +
> > +    if (last_p && !m_stats[dim_indx].elts_counted)
> > +      {
> > +	m_stats[dim_indx].nelts = m_elts;
> > +	m_stats[dim_indx].elts_counted = true;
> > +      }
> >    }
> >  
> >  private:
> > +  /* Called to print outstanding repeated elements of ELT_TYPE starting
> > +     at offset ELT_OFF from the start of the parent object.  */
> > +  void process_outstanding_elements (struct type *elt_type, LONGEST elt_off)
> > +  {
> > +    LONGEST nrepeats = m_nrepeats;
> > +
> > +    m_nrepeats = 0;
> > +    if (nrepeats >= m_options->repeat_count_threshold)
> > +      {
> > +	annotate_elt_rep (nrepeats + 1);
> > +	fprintf_filtered (m_stream, "%p[<repeats %s times>%p]",
> > +			  metadata_style.style ().ptr (),
> > +			  plongest (nrepeats + 1),
> > +			  nullptr);
> > +	annotate_elt_rep_end ();
> > +      }
> > +    else
> > +      {
> > +	/* Extract the element value from the parent value.  */
> > +	struct value *e_val = value_from_component (m_val, elt_type, elt_off);
> > +
> > +	for (LONGEST i = nrepeats; i > 0; i--)
> > +	  {
> > +	    common_val_print (e_val, m_stream, m_recurse, m_options,
> > +			      current_language);
> > +	    if (i > 1)
> > +	      fputs_filtered (", ", m_stream);
> > +	  }
> > +      }
> > +  }
> > +
> > +  /* Called to compare two VAL elements of ELT_TYPE at offsets OFFSET1
> > +     and OFFSET2 each.  Handle subarrays recursively, because they may
> > +     have been sliced and we do not want to compare any memory contents
> > +     present between the slices requested.  */
> > +  bool
> > +  dimension_contents_eq (const struct value *val, struct type *type,
> > +			 LONGEST offset1, LONGEST offset2)
> > +  {
> > +    if (type->code () == TYPE_CODE_ARRAY
> > +	&& TYPE_TARGET_TYPE (type)->code () != TYPE_CODE_CHAR)
> > +      {
> > + 	/* Extract the range, and get lower and upper bounds.  */
> 
> You have a space before tab here.

 Fixed, good catch!

> > @@ -180,6 +387,19 @@ class fortran_array_printer_impl : publi
> >    /* The print control options.  Gives us the maximum number of elements to
> >       print, and is passed through to each element that we print.  */
> >    const struct value_print_options *m_options = nullptr;
> > +
> > +  /* Dimension tracker.  */
> > +  LONGEST m_dimension;
> > +
> > +  /* Repetition tracker.  */
> > +  LONGEST m_nrepeats;
> > +
> > +  /* Element tracker.  */
> > +  struct type *m_elt_type_prev;
> > +  LONGEST m_elt_off_prev;
> > +
> > +  /* Per-dimension stats.  */
> > +  std::vector<struct dimension_stats> m_stats;
> 
> I'd like to see some of these comments expanded slightly to give more
> information about how they are used.

 Fixed (hopefully).

 Let me know if have any concerns about my explanations and/or the 
updates made.

  Maciej

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

* Re: [PATCH 4/6] Add `set print repeats' tests for C/C++ arrays
  2021-12-15 15:33   ` Andrew Burgess
@ 2022-01-08 16:26     ` Maciej W. Rozycki
  0 siblings, 0 replies; 19+ messages in thread
From: Maciej W. Rozycki @ 2022-01-08 16:26 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On Wed, 15 Dec 2021, Andrew Burgess wrote:

> > Add `set print repeats' tests for C/C++ arrays, complementing one for 
> > Fortran arrays and covering the different interpretation of the `set 
> > print elements' setting in particular where the per-dimension count of 
> > the elements handled is matched against the trigger rather than the 
> > total element count as with Fortran arrays.
> 
> I know we disagree on this topic, but I would, one day, like to see
> the C/C++ array printing behave as the Fortran array printing does, as
> that makes much more sense to me.

 I'm not sure if there's much disagreement between us really.  I just 
think there may be use cases, including existing ones, where the C/C++ 
printer's interpretation is required.  It must have been made this way for 
a reason after all -- if not for one, this code wouldn't have been written 
in the first place, would it?

 So what I think we're ultimately after it is a way to switch between the 
two variants regardless of the language being handled, possibly with the 
defaults remaining as they are now.

> But, adding tests for GDB's current behaviour is definitely a good
> thing, so I'm happy to see this going in, with one change...

 Well, I think we need coverage either way, because otherwise we can't 
easily see if things continue working the way intended.

> Given that the C and C++ tests are almost identical, I think you
> should consider just adding one copy in gdb.base and compiling it as
> both C and C++.
> 
> For inspiration you can look at these files:
> 
>   gdb/testsuite/gdb.base/infcall-nested-structs-c.exp
>   gdb/testsuite/gdb.base/infcall-nested-structs-c++.exp
>   gdb/testsuite/gdb.base/infcall-nested-structs.exp.tcl

 Thanks for the hint.  I chose to keep the C++ test in gdb.cp/ as I think 
it's the way it should be (and any existing mess ought to be cleaned up 
too) so that say "RUNTESTFLAGS=gdb.cp/*.exp" selects all the C++ testing, 
but otherwise followed the approach.

  Maciej

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

* Re: [PATCH 5/6] Respect `set print array-indexes' with Fortran arrays
  2021-12-15 16:49   ` Andrew Burgess
@ 2022-01-08 16:27     ` Maciej W. Rozycki
  0 siblings, 0 replies; 19+ messages in thread
From: Maciej W. Rozycki @ 2022-01-08 16:27 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On Wed, 15 Dec 2021, Andrew Burgess wrote:

> > Index: src/gdb/f-array-walker.h
> > ===================================================================
> > --- src.orig/gdb/f-array-walker.h
> > +++ src/gdb/f-array-walker.h
> > @@ -138,7 +138,8 @@ struct fortran_array_walker_base_impl
> >       true only when this is the last element that will be processed in
> >       this dimension.  */
> >    void process_dimension (std::function<void (struct type *, int, bool)> walk_1,
> > -			  struct type *elt_type, LONGEST elt_off, bool last_p)
> > +			  struct type *elt_type, LONGEST elt_off,
> > +			  struct type *, LONGEST, bool last_p)
> 
> I'd like to see the new arguments given names, and the comment
> extended to explain what they're for, given this is the base
> implementation from which others inherit it seems like this is the
> obvious place someone would look to figure this sort of thing out.

 That is the proper C++ syntax for unused parameters, preferred for GCC, 
the style of which we follow according to our wiki, which I double-checked 
on this occasion as I wrote this code, as far as C++ usage is concerned, 
over `__attribute__ ((__unused__))' since the switch to C++.  And I wasn't 
aware we chose to use `-Wno-unused' instead, which may not be as clean as 
the standard C++ syntax.  I think this divergence from the GCC C++ coding 
style needs to be clearly documented in our wiki.

 I've added the missing argument names then here and elsewhere (a viable 
alternative would be to have the argument names commented out).
  
> > @@ -223,6 +225,8 @@ class fortran_array_walker
> >      if (m_nss != m_ndimensions)
> >        {
> >  	struct type *subarray_type = TYPE_TARGET_TYPE (check_typedef (type));
> > +	gdb_assert (range_type->code () == TYPE_CODE_RANGE);
> 
> I think this assert should move up to immediately after we fetch
> range_type, I'm pretty sure that if range_type isn't TYPE_CODE_RANGE
> then the call to get_discrete_bounds will have already gone wrong.

 Well, I have checked and `get_discrete_bounds' looks prepared to several 
other types, specifically: TYPE_CODE_ENUM, TYPE_CODE_BOOL, TYPE_CODE_INT 
and TYPE_CODE_CHAR, so this assertion is only for TYPE_TARGET_TYPE really, 
so for clarity I've left it right before the invocation of the latter 
macro.

> > @@ -260,7 +264,8 @@ class fortran_array_walker
> >  		elt_type = resolve_dynamic_type (elt_type, {}, e_address);
> >  	      }
> >  
> > -	    m_impl.process_element (elt_type, elt_off, (i == upperbound));
> > +	    m_impl.process_element (elt_type, elt_off, range_type, i,
> > +				    i == upperbound);
> 
> This seems a little weird, you're passing the range_type through to
> the index_type parameter?  Is this really what you mean?

 It's a stupid oversight on my side; this should have been `index_type' in 
both legs of the conditional.  I have adjusted code accordingly (though 
it's now gone owing to the change described below).

> Assuming you mean to pass TYPE_TARGET_TYPE(range_type) here, then the
> index_type ends up being passed through to both process_element and
> process_dimension.  You then end up placing the index_type into a
> member variable within the m_impl.  I wonder if it would be better to
> pass the index_type to start_dimension, and stash it there, then we'd
> only need to pass the index value through maybe?  Or, maybe there
> would be problems with handling multi-dimensional arrays?  I guess
> it's pretty hard to actually uncover bugs in this area as the
> index_type is almost always the same I think....

 I chewed your thoughts over and realised that if we pass `index_type' via 
`start_dimension' then not only some code complication is removed, but if 
we stash it per-dimension, then we'll have no issue if we ever need to use 
different types for individual dimensions.  And the rank of an array is at 
most seven in Fortran, so it's not like it will consume a lot of memory.

 See v2 for how the result looks like.

  Maciej

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

* Re: [PATCH 6/6] Add `set print array-indexes' tests for C/C++ arrays
  2021-12-15 16:51   ` Andrew Burgess
@ 2022-01-08 16:27     ` Maciej W. Rozycki
  0 siblings, 0 replies; 19+ messages in thread
From: Maciej W. Rozycki @ 2022-01-08 16:27 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On Wed, 15 Dec 2021, Andrew Burgess wrote:

> > Add `set print array-indexes' tests for C/C++ arrays, complementing one 
> > for Fortran arrays.
> > ---
> >  gdb/testsuite/gdb.base/array-indices.exp |  174 ++++++++++++++++++++++++++++++
> >  gdb/testsuite/gdb.cp/array-indices.exp   |  176 +++++++++++++++++++++++++++++++
> 
> If the previous C/C++ tests are combined then these would naturally be
> combined too.  Otherwise LGTM.

 Updated accordingly.  Thank you for your review!

  Maciej

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

end of thread, other threads:[~2022-01-08 16:27 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-11 11:46 [PATCH 0/6] Make Fortran support respect more `set print' settings Maciej W. Rozycki
2021-12-11 11:47 ` [PATCH 1/6] Initialize `m_ndimensions' in the member initializer list Maciej W. Rozycki
2021-12-15 13:18   ` Andrew Burgess
2021-12-17 15:03     ` Maciej W. Rozycki
2021-12-11 11:47 ` [PATCH 2/6] Avoid redundant operations in `fortran_array_walker' Maciej W. Rozycki
2021-12-15 13:19   ` Andrew Burgess
2021-12-17 15:04     ` Maciej W. Rozycki
2021-12-11 11:47 ` [PATCH 3/6] Respect `set print repeats' with Fortran arrays Maciej W. Rozycki
2021-12-15 15:18   ` Andrew Burgess
2022-01-08 16:25     ` Maciej W. Rozycki
2021-12-11 11:47 ` [PATCH 4/6] Add `set print repeats' tests for C/C++ arrays Maciej W. Rozycki
2021-12-15 15:33   ` Andrew Burgess
2022-01-08 16:26     ` Maciej W. Rozycki
2021-12-11 11:47 ` [PATCH 5/6] Respect `set print array-indexes' with Fortran arrays Maciej W. Rozycki
2021-12-15 16:49   ` Andrew Burgess
2022-01-08 16:27     ` Maciej W. Rozycki
2021-12-11 11:48 ` [PATCH 6/6] Add `set print array-indexes' tests for C/C++ arrays Maciej W. Rozycki
2021-12-15 16:51   ` Andrew Burgess
2022-01-08 16:27     ` Maciej W. Rozycki

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