Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 00/10] [gdb] Add superblocks range loops
@ 2026-05-01 12:44 Tom de Vries
  2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
                   ` (10 more replies)
  0 siblings, 11 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
  To: gdb-patches

This series attempts to rewrite code like this:
...
  while (block != NULL)
    {
      ...
      block = block->superblock ();
    }
...
using range loops.

I haven't rewritten loops in block.c itself.

An RFC was submitted here [1].

Changes in v1:
- commit first two patches of RFC
- add a patch adding uses of block::containing_function
- add patches adding and using block::containing_function_block
- add next_iterator unit test, also excercising incomplete type case
- modernize next_iterator by replacing typedef with using
- rewrite base_next_iterator to use Curiously Recurring Template Pattern
- use using to import constructors in next_iterator
- move comment part showing "using a pointer-to-member template argument
  T::next" to commit message
- change names to block_and_superblocks block_and_superblocks_in_fn
- add some missing comments
- complete the refactoring using the range loops
- clarify behaviour of block_and_superblocks_in_fn in relation to static and
  global blocks in commit message
- also avoid static and global blocks in function_block_iterator::next

[1] https://sourceware.org/pipermail/gdb-patches/2026-April/226720.html

Tom de Vries (10):
  [gdb] Use block::containing_function
  [gdb] Factor out block::containing_function_block
  [gdb] Use block::containing_function_block
  [gdb] Add unit test for next_iterator
  [gdbsupport] Use using instead of typedef in next_iterator
  [gdbsupport] Factor out base_next_iterator
  [gdb] Add block::block_and_superblocks
  [gdb] Use block::block_and_superblocks
  [gdb] Add block::block_and_superblocks_in_fn
  [gdb] Use block::block_and_superblocks_in_fn

 gdb/Makefile.in                         |   1 +
 gdb/ada-lang.c                          |  61 ++++------
 gdb/block.c                             |  18 ++-
 gdb/block.h                             | 102 ++++++++++++++++
 gdb/blockframe.c                        |  11 +-
 gdb/compile/compile-c-symbols.c         |  10 +-
 gdb/compile/compile-object-load.c       |   8 +-
 gdb/cp-namespace.c                      |   6 +-
 gdb/cp-support.c                        |   8 +-
 gdb/d-namespace.c                       |   6 +-
 gdb/dwarf2/line-program.c               |  24 ++--
 gdb/f-valprint.c                        |  19 ++-
 gdb/go-lang.c                           |  31 ++---
 gdb/guile/scm-frame.c                   |  13 +-
 gdb/infrun.c                            |  10 +-
 gdb/inline-frame.c                      |  45 ++++---
 gdb/linespec.c                          |  22 ++--
 gdb/mi/mi-cmd-stack.c                   | 155 +++++++++++-------------
 gdb/python/py-frame.c                   |  13 +-
 gdb/python/py-unwind.c                  |  15 +--
 gdb/stack.c                             |  15 +--
 gdb/symmisc.c                           |   9 +-
 gdb/symtab.c                            |  69 ++++++-----
 gdb/tracepoint.c                        |   9 +-
 gdb/unittests/next-iterator-selftests.c | 105 ++++++++++++++++
 gdbsupport/next-iterator.h              |  48 +++++---
 gdbsupport/safe-iterator.h              |  12 +-
 27 files changed, 511 insertions(+), 334 deletions(-)
 create mode 100644 gdb/unittests/next-iterator-selftests.c


base-commit: 27d21139e356aca4b77d32e81105c465f1e6650c
-- 
2.51.0


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

* [PATCH 01/10] [gdb] Use block::containing_function
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
  2026-05-01 12:44 ` [PATCH 02/10] [gdb] Factor out block::containing_function_block Tom de Vries
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
  To: gdb-patches

Add uses of block::containing_function.
---
 gdb/go-lang.c | 31 ++++++++++++-------------------
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index 3b388c961fa..657679f3fe8 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -430,28 +430,21 @@ go_symbol_package_name (const struct symbol *sym)
 gdb::unique_xmalloc_ptr<char>
 go_block_package_name (const struct block *block)
 {
-  while (block != NULL)
-    {
-      struct symbol *function = block->function ();
-
-      if (function != NULL)
-	{
-	  gdb::unique_xmalloc_ptr<char> package_name
-	    = go_symbol_package_name (function);
-
-	  if (package_name != NULL)
-	    return package_name;
+  struct symbol *function
+    = block != nullptr ? block->containing_function () : nullptr;
+  if (function == nullptr)
+    return nullptr;
 
-	  /* Stop looking if we find a function without a package name.
-	     We're most likely outside of Go and thus the concept of the
-	     "current" package is gone.  */
-	  return NULL;
-	}
+  gdb::unique_xmalloc_ptr<char> package_name
+    = go_symbol_package_name (function);
 
-      block = block->superblock ();
-    }
+  if (package_name != nullptr)
+    return package_name;
 
-  return NULL;
+  /* Stop looking if we find a function without a package name.
+     We're most likely outside of Go and thus the concept of the
+     "current" package is gone.  */
+  return nullptr;
 }
 
 /* See language.h.  */
-- 
2.51.0


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

* [PATCH 02/10] [gdb] Factor out block::containing_function_block
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
  2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
  2026-05-01 12:44 ` [PATCH 03/10] [gdb] Use block::containing_function_block Tom de Vries
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
  To: gdb-patches

Factor out new function block::containing_function_block out of
block::containing_function.
---
 gdb/block.c | 18 ++++++++++++++----
 gdb/block.h |  5 +++++
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/gdb/block.c b/gdb/block.c
index e7424c52aff..7b006617d1a 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -99,15 +99,25 @@ block::linkage_function () const
 
 /* See block.h.  */
 
-struct symbol *
-block::containing_function () const
+const struct block *
+block::containing_function_block () const
 {
   const block *bl = this;
 
-  while (bl->function () == NULL && bl->superblock () != NULL)
+  while (bl->function () == nullptr && bl->superblock () != nullptr)
     bl = bl->superblock ();
 
-  return bl->function ();
+  return bl->function () != nullptr ? bl : nullptr;
+}
+
+/* See block.h.  */
+
+struct symbol *
+block::containing_function () const
+{
+  const block *bl = containing_function_block ();
+
+  return bl != nullptr ? bl->function () : nullptr;
 }
 
 /* See block.h.  */
diff --git a/gdb/block.h b/gdb/block.h
index cd02006f860..b70b27f6509 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -258,6 +258,11 @@ struct block : public allocate_on_obstack<block>
 
   struct symbol *containing_function () const;
 
+  /* Return the block for the closest enclosing function, which might be an
+     inline function.  */
+
+  const struct block *containing_function_block () const;
+
   /* Return the static block associated with this block.  Return NULL
      if block is a global block.  */
 
-- 
2.51.0


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

* [PATCH 03/10] [gdb] Use block::containing_function_block
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
  2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
  2026-05-01 12:44 ` [PATCH 02/10] [gdb] Factor out block::containing_function_block Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
  2026-05-01 12:44 ` [PATCH 04/10] [gdb] Add unit test for next_iterator Tom de Vries
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
  To: gdb-patches

Add uses of block::containing_function_block.
---
 gdb/guile/scm-frame.c  | 13 ++++++-------
 gdb/linespec.c         | 15 +++++++--------
 gdb/python/py-frame.c  | 13 ++++++-------
 gdb/python/py-unwind.c | 13 +++++--------
 4 files changed, 24 insertions(+), 30 deletions(-)

diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 722a754caab..ffcc3049074 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -598,7 +598,7 @@ static SCM
 gdbscm_frame_block (SCM self)
 {
   frame_smob *f_smob;
-  const struct block *block = NULL, *fn_block;
+  const struct block *block = nullptr;
   bool found = false;
 
   f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
@@ -625,12 +625,11 @@ gdbscm_frame_block (SCM self)
 				   _("<gdb:frame>"));
     }
 
-  for (fn_block = block;
-       fn_block != NULL && fn_block->function () == NULL;
-       fn_block = fn_block->superblock ())
-    continue;
-
-  if (block == NULL || fn_block == NULL || fn_block->function () == NULL)
+  const struct block *fn_block
+    = (block != nullptr
+       ? block->containing_function_block ()
+       : nullptr);
+  if (fn_block == nullptr)
     {
       scm_misc_error (FUNC_NAME, _("cannot find block for frame"),
 		      scm_list_1 (self));
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 45e12e09272..6ed4b4553d3 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -3860,17 +3860,16 @@ find_label_symbols (struct linespec_state *self,
       set_current_program_space (self->program_space);
       block = get_current_search_block ();
 
-      for (;
-	   block && !block->function ();
-	   block = block->superblock ())
-	;
-
-      if (!block)
+      const struct block *fn_block
+	= (block != nullptr
+	   ? block->containing_function_block ()
+	   : nullptr);
+      if (fn_block == nullptr)
 	return {};
 
-      fn_sym = block->function ();
+      fn_sym = fn_block->function ();
 
-      find_label_symbols_in_block (block, name, fn_sym, completion_mode,
+      find_label_symbols_in_block (fn_block, name, fn_sym, completion_mode,
 				   &result, label_funcs_ret);
     }
   else
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 1420d2ac5b9..42a281b9712 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -299,7 +299,7 @@ static PyObject *
 frapy_block (PyObject *self, PyObject *args)
 {
   frame_info_ptr frame;
-  const struct block *block = NULL, *fn_block;
+  const struct block *block = nullptr;
 
   try
     {
@@ -311,12 +311,11 @@ frapy_block (PyObject *self, PyObject *args)
       return gdbpy_handle_gdb_exception (nullptr, except);
     }
 
-  for (fn_block = block;
-       fn_block != NULL && fn_block->function () == NULL;
-       fn_block = fn_block->superblock ())
-    ;
-
-  if (block == NULL || fn_block == NULL || fn_block->function () == NULL)
+  const struct block *fn_block
+    = (block != nullptr
+       ? block->containing_function_block ()
+       : nullptr);
+  if (fn_block == nullptr)
     {
       PyErr_SetString (PyExc_RuntimeError,
 		       _("Cannot locate block for frame."));
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index dcf86f7db3d..6dc5e11cf87 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -646,14 +646,11 @@ pending_framepy_block (PyObject *self, PyObject *args)
       return gdbpy_handle_gdb_exception (nullptr, except);
     }
 
-  for (fn_block = block;
-       fn_block != nullptr && fn_block->function () == nullptr;
-       fn_block = fn_block->superblock ())
-    ;
-
-  if (block == nullptr
-      || fn_block == nullptr
-      || fn_block->function () == nullptr)
+  const struct block *fn_block
+    = (block != nullptr
+       ? block->containing_function_block ()
+       : nullptr);
+  if (fn_block == nullptr)
     {
       PyErr_SetString (PyExc_RuntimeError,
 		       _("Cannot locate block for frame."));
-- 
2.51.0


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

* [PATCH 04/10] [gdb] Add unit test for next_iterator
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (2 preceding siblings ...)
  2026-05-01 12:44 ` [PATCH 03/10] [gdb] Use block::containing_function_block Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
  2026-05-01 12:44 ` [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator Tom de Vries
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
  To: gdb-patches

I noticed that next_iterator doesn't have a selftest.  Add this.
---
 gdb/Makefile.in                         |   1 +
 gdb/unittests/next-iterator-selftests.c | 105 ++++++++++++++++++++++++
 2 files changed, 106 insertions(+)
 create mode 100644 gdb/unittests/next-iterator-selftests.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e38ba95eebd..8b1a40dad7e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -476,6 +476,7 @@ SELFTESTS_SRCS = \
 	unittests/lookup_name_info-selftests.c \
 	unittests/memory-map-selftests.c \
 	unittests/memrange-selftests.c \
+	unittests/next-iterator-selftests.c \
 	unittests/offset-type-selftests.c \
 	unittests/observable-selftests.c \
 	unittests/packed-selftests.c \
diff --git a/gdb/unittests/next-iterator-selftests.c b/gdb/unittests/next-iterator-selftests.c
new file mode 100644
index 00000000000..8934e5bbaa0
--- /dev/null
+++ b/gdb/unittests/next-iterator-selftests.c
@@ -0,0 +1,105 @@
+/* Self tests for the next_iterator class.
+
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "gdbsupport/selftest.h"
+#include "gdbsupport/next-iterator.h"
+#include <vector>
+
+namespace selftests {
+namespace next_iterator {
+
+struct list;
+using list_iterator = ::next_iterator<struct list>;
+using list_range = next_range<struct list>;
+
+/* The next_iterator allows usage with an incomplete type, provided the type
+   is defined later in the same file.  While not essential to its functioning,
+   we're currently using this property in the sources, so check/demonstrate
+   it.  */
+
+static void
+test_next_iterator_incomplete_type (struct list *l)
+{
+  list_iterator begin (l);
+  list_iterator end;
+
+  unsigned cnt = 0;
+  list_iterator i;
+  for (i = begin; i != end; ++i)
+    cnt++;
+  SELF_CHECK (cnt == 3);
+}
+
+struct list
+{
+  int i;
+  struct list *next;
+};
+
+static void
+test_next_iterator ()
+{
+  struct list a = { 1, nullptr };
+  struct list b = { 2, &a };
+  struct list c = { 3, &b };
+
+  /* Constructor with parameter.  */
+  list_iterator begin (&c);
+
+  /* Constructor without parameter.  */
+  list_iterator end;
+
+  /* Operator*.  */
+  SELF_CHECK (*begin == &c);
+  SELF_CHECK (*end == nullptr);
+
+  /* Operator==, operator!=.  */
+  SELF_CHECK (begin == begin);
+  SELF_CHECK (end == end);
+  SELF_CHECK (begin != end);
+
+  /* Operator++.  */
+  list_iterator i (&c);
+  ++i;
+  SELF_CHECK (*i == &b);
+
+  /* Loop using iterators.  */
+  std::vector<int> expected = {3, 2, 1};
+  std::vector<int> v;
+  for (i = begin; i != end; ++i)
+    v.push_back ((*i)->i);
+  SELF_CHECK (v == expected);
+
+  /* Loop using range.  */
+  v.clear ();
+  for (auto l : list_range (begin))
+    v.push_back (l->i);
+  SELF_CHECK (v == expected);
+
+  test_next_iterator_incomplete_type (&c);
+}
+
+} /* namespace next_iterator */
+} /* namespace selftests */
+
+INIT_GDB_FILE (next_iterator_selftests)
+{
+  selftests::register_test ("next-iterator",
+			    selftests::next_iterator::test_next_iterator);
+}
-- 
2.51.0


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

* [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (3 preceding siblings ...)
  2026-05-01 12:44 ` [PATCH 04/10] [gdb] Add unit test for next_iterator Tom de Vries
@ 2026-05-01 12:44 ` Tom de Vries
  2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:44 UTC (permalink / raw)
  To: gdb-patches

Use using instead of typedef in next_iterator.  While we're at it, do the same
in basic_safe_iterator.

Suggested-By: Simon Marchi <simon.marchi@polymtl.ca>
Co-Authored-By: Simon Marchi <simon.marchi@polymtl.ca>
---
 gdbsupport/next-iterator.h | 12 ++++++------
 gdbsupport/safe-iterator.h | 12 ++++++------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/gdbsupport/next-iterator.h b/gdbsupport/next-iterator.h
index 0c90428d349..9f0aba7f8c4 100644
--- a/gdbsupport/next-iterator.h
+++ b/gdbsupport/next-iterator.h
@@ -28,12 +28,12 @@
 template<typename T>
 struct next_iterator
 {
-  typedef next_iterator self_type;
-  typedef T *value_type;
-  typedef T *&reference;
-  typedef T **pointer;
-  typedef std::forward_iterator_tag iterator_category;
-  typedef int difference_type;
+  using self_type = next_iterator;
+  using value_type = T *;
+  using reference = T *&;
+  using pointer = T **;
+  using iterator_category = std::forward_iterator_tag;
+  using difference_type = int;
 
   explicit next_iterator (T *item)
     : m_item (item)
diff --git a/gdbsupport/safe-iterator.h b/gdbsupport/safe-iterator.h
index 3e5d1140179..6c5a2901c7e 100644
--- a/gdbsupport/safe-iterator.h
+++ b/gdbsupport/safe-iterator.h
@@ -43,12 +43,12 @@ template<typename Iterator>
 class basic_safe_iterator
 {
 public:
-  typedef basic_safe_iterator self_type;
-  typedef typename Iterator::value_type value_type;
-  typedef typename Iterator::reference reference;
-  typedef typename Iterator::pointer pointer;
-  typedef typename Iterator::iterator_category iterator_category;
-  typedef typename Iterator::difference_type difference_type;
+  using self_type = basic_safe_iterator;
+  using value_type = typename Iterator::value_type;
+  using reference = typename Iterator::reference;
+  using pointer = typename Iterator::pointer;
+  using iterator_category = typename Iterator::iterator_category;
+  using difference_type = typename Iterator::difference_type;
 
   /* Construct the iterator using the underlying iterator BEGIN; the end
      iterator is default constructed.  */
-- 
2.51.0


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

* [PATCH 06/10] [gdbsupport] Factor out base_next_iterator
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (4 preceding siblings ...)
  2026-05-01 12:44 ` [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
  2026-05-08 19:17   ` Tom Tromey
  2026-05-01 12:45 ` [PATCH 07/10] [gdb] Add block::block_and_superblocks Tom de Vries
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
  To: gdb-patches

Template struct next_iterator<T> allows iterating over the "next" field of T.

I decided to generalize this to be able to use any field.

A first thought was to use macros, but nowadays we try to do things more in
native c++, so I didn't explore that further.

Instead, this patch factors out base_next_iterator, which contains all parts
not specific to "next", in other words, everything except the operator++.

I also explored using a pointer-to-member template argument T::next:
...
     template<typename T, auto F = &T::next>
     struct next_iterator
     {
       ...
       self_type &operator++ ()
       {
	 m_item = m_item->*F;
	 return *this;
       }
       ...
     }
...
but that meant that using an incomplete T was no longer allowed (see
test_next_iterator_incomplete_type), so it's not a drop-in replacement.
---
 gdbsupport/next-iterator.h | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/gdbsupport/next-iterator.h b/gdbsupport/next-iterator.h
index 9f0aba7f8c4..feee2c2a7c7 100644
--- a/gdbsupport/next-iterator.h
+++ b/gdbsupport/next-iterator.h
@@ -21,27 +21,27 @@
 
 #include "gdbsupport/iterator-range.h"
 
-/* An iterator that uses the 'next' field of a type to iterate.  This
-   can be used with various GDB types that are stored as linked
-   lists.  */
+/* An iterator base class for iterating over a field of a type.  In order to
+   form a functioning iterator, classes inheriting this should define a next
+   function, which determines the actual field that is iterated over.  */
 
-template<typename T>
-struct next_iterator
+template<typename T, class D>
+struct base_next_iterator
 {
-  using self_type = next_iterator;
+  using self_type = base_next_iterator;
   using value_type = T *;
   using reference = T *&;
   using pointer = T **;
   using iterator_category = std::forward_iterator_tag;
   using difference_type = int;
 
-  explicit next_iterator (T *item)
+  explicit base_next_iterator (T *item)
     : m_item (item)
   {
   }
 
   /* Create a one-past-the-end iterator.  */
-  next_iterator ()
+  base_next_iterator ()
     : m_item (nullptr)
   {
   }
@@ -63,15 +63,31 @@ struct next_iterator
 
   self_type &operator++ ()
   {
-    m_item = m_item->next;
+    m_item = static_cast<D *>(this)->next ();
     return *this;
   }
 
-private:
+protected:
 
   T *m_item;
 };
 
+/* An iterator that uses the 'next' field of a type to iterate.  This
+   can be used with various GDB types that are stored as linked
+   lists.  Note that we're using CRTP here.  */
+
+template<typename T>
+struct next_iterator : base_next_iterator<T, next_iterator<T>>
+{
+  using base_next_iterator<T, next_iterator<T>>::base_next_iterator;
+  using base_next_iterator<T, next_iterator<T>>::m_item;
+
+  T *next ()
+  {
+    return m_item->next;
+  }
+};
+
 /* A convenience wrapper to make a range type around a next_iterator.  */
 
 template <typename T>
-- 
2.51.0


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

* [PATCH 07/10] [gdb] Add block::block_and_superblocks
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (5 preceding siblings ...)
  2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
  2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
  To: gdb-patches

Add a function block::block_and_superblocks that can be used to transform:
...
  while (block != NULL)
    {
      ...
      block = block->superblock ();
    }
...
into:
...
  for (auto b : block::block_and_superblocks (block))
    {
      ...
    }
...
---
 gdb/block.h | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/gdb/block.h b/gdb/block.h
index b70b27f6509..ff5203ae4c6 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -108,6 +108,27 @@ struct blockranges
 
 struct block : public allocate_on_obstack<block>
 {
+  /* Variant of next_iterator using the superblock field instead of next.  */
+  struct superblock_iterator
+    : base_next_iterator<const block, superblock_iterator>
+  {
+    typedef superblock_iterator self_type;
+
+    explicit superblock_iterator (value_type item)
+      : base_next_iterator (item)
+    {
+    }
+
+    superblock_iterator () = default;
+
+    value_type next ()
+    {
+      return m_item->superblock ();
+    }
+  };
+
+  using superblock_range = iterator_range<superblock_iterator>;
+
   /* Return this block's start address.  */
   CORE_ADDR start () const
   { return m_start; }
@@ -311,6 +332,26 @@ struct block : public allocate_on_obstack<block>
 
   struct dynamic_prop *static_link () const;
 
+  /* Return a range adapter that iterates over this block and its
+     superblocks.  */
+
+  superblock_range block_and_superblocks () const
+  {
+    superblock_range::iterator begin (this);
+
+    return superblock_range (std::move (begin));
+  }
+
+  /* Return a range adapter that iterates over B and its superblocks.  */
+
+  static superblock_range block_and_superblocks (const block *b)
+  {
+    if (b == nullptr)
+      return superblock_range ();
+
+    return b->block_and_superblocks ();
+  }
+
   /* Return true if block A is lexically nested within this block, or
      if A and this block have the same pc range.  Return false
      otherwise.  If ALLOW_NESTED is true, then block A is considered
-- 
2.51.0


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

* [PATCH 08/10] [gdb] Use block::block_and_superblocks
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (6 preceding siblings ...)
  2026-05-01 12:45 ` [PATCH 07/10] [gdb] Add block::block_and_superblocks Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
  2026-05-08 19:41   ` Tom Tromey
  2026-05-01 12:45 ` [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn Tom de Vries
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
  To: gdb-patches

Add uses of block::block_and_superblocks.
---
 gdb/ada-lang.c                    | 18 ++++------
 gdb/blockframe.c                  | 11 +++---
 gdb/compile/compile-object-load.c |  8 +++--
 gdb/cp-namespace.c                |  6 ++--
 gdb/cp-support.c                  |  8 ++---
 gdb/d-namespace.c                 |  6 ++--
 gdb/dwarf2/line-program.c         | 24 +++++--------
 gdb/infrun.c                      | 10 +++---
 gdb/inline-frame.c                | 45 +++++++++++-------------
 gdb/linespec.c                    |  7 ++--
 gdb/symmisc.c                     |  9 +++--
 gdb/symtab.c                      | 58 ++++++++++++++++++-------------
 12 files changed, 101 insertions(+), 109 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 71a338ce17e..6eb928b445d 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -5402,17 +5402,15 @@ ada_add_local_symbols (std::vector<struct block_symbol> &result,
 		       const lookup_name_info &lookup_name,
 		       const struct block *block, domain_search_flags domain)
 {
-  while (block != NULL)
+  for (auto b : block::block_and_superblocks (block))
     {
-      ada_add_block_symbols (result, block, lookup_name, domain, NULL);
+      ada_add_block_symbols (result, b, lookup_name, domain, nullptr);
 
       /* If we found a non-function match, assume that's the one.  We
 	 only check this when finding a function boundary, so that we
 	 can accumulate all results from intervening blocks first.  */
-      if (block->function () != nullptr && is_nonfunction (result))
+      if (b->function () != nullptr && is_nonfunction (result))
 	return;
-
-      block = block->superblock ();
     }
 }
 
@@ -13825,9 +13823,7 @@ class ada_language : public language_defn
     /* Search upwards from currently selected frame (so that we can
        complete on local vars.  */
 
-    for (const block *b = get_selected_block (0);
-	 b != nullptr;
-	 b = b->superblock ())
+    for (auto b : block::block_and_superblocks (get_selected_block (0)))
       {
 	if (b->is_static_block ())
 	  surrounding_static_block = b;   /* For elmin of dups */
@@ -13852,9 +13848,9 @@ class ada_language : public language_defn
 	auto callback = [&] (compunit_symtab *s)
 	  {
 	    QUIT;
-	    for (const block *b = s->blockvector ()->static_block ();
-		 b != nullptr;
-		 b = b->superblock ())
+	    const struct block *static_block
+	      = s->blockvector ()->static_block ();
+	    for (auto b : block::block_and_superblocks (static_block))
 	      {
 		/* Don't do this block twice.  */
 		if (b == surrounding_static_block)
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 8aafa6ffe57..5c981748cbc 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -69,13 +69,14 @@ get_frame_block (const frame_info_ptr &frame, CORE_ADDR *addr_in_block)
 
   inline_count = frame_inlined_callees (frame);
 
-  while (inline_count > 0)
+  auto range = bl->block_and_superblocks ();
+  for (auto b = range.begin (); b != range.end (); ++b, bl = *b)
     {
-      if (bl->inlined_p ())
-	inline_count--;
+      if (inline_count <= 0)
+	break;
 
-      bl = bl->superblock ();
-      gdb_assert (bl != NULL);
+      if ((*b)->inlined_p ())
+	inline_count--;
     }
 
   return bl;
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index 4ea924582fb..32c6fe0bacf 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -443,10 +443,12 @@ get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
 	continue;
 
       function_block = block;
-      while (function_block != bv->static_block ()
-	     && function_block != bv->global_block ())
+      for (auto b : block::block_and_superblocks (block))
 	{
-	  function_block = function_block->superblock ();
+	  if (b == bv->static_block () || b == bv->global_block ())
+	    break;
+
+	  function_block = b->superblock ();
 	  function = function_block->function ();
 	  if (function != NULL)
 	    break;
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index c8cd5c245aa..534f2d0b8f9 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -613,13 +613,11 @@ cp_lookup_symbol_via_all_imports (const char *scope, const char *name,
 {
   struct block_symbol sym;
 
-  while (block != NULL)
+  for (auto b : block::block_and_superblocks (block))
     {
-      sym = cp_lookup_symbol_via_imports (scope, name, block, domain, 0, 1);
+      sym = cp_lookup_symbol_via_imports (scope, name, b, domain, 0, 1);
       if (sym.symbol != nullptr)
 	return sym;
-
-      block = block->superblock ();
     }
 
   return {};
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index d040ad79469..c04a5120380 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -1408,15 +1408,11 @@ add_symbol_overload_list_using (const char *func_name,
 				const char *the_namespace,
 				std::vector<symbol *> *overload_list)
 {
-  const struct block *block;
-
   /* First, go through the using directives.  If any of them apply,
      look in the appropriate namespaces for new functions to match
      on.  */
 
-  for (block = get_selected_block (0);
-       block != NULL;
-       block = block->superblock ())
+  for (auto block : block::block_and_superblocks (get_selected_block (0)))
     for (using_direct *current : block->get_using ())
       {
 	/* Prevent recursive calls.  */
@@ -1459,7 +1455,7 @@ add_symbol_overload_list_qualified (const char *func_name,
   /* Search upwards from currently selected frame (so that we can
      complete on local vars.  */
 
-  for (const block *b = selected_block; b != nullptr; b = b->superblock ())
+  for (auto b : block::block_and_superblocks (selected_block))
     add_symbol_overload_list_block (func_name, b, overload_list);
 
   const block *surrounding_static_block = (selected_block == nullptr
diff --git a/gdb/d-namespace.c b/gdb/d-namespace.c
index 34b90c0ed93..a8bb90320c3 100644
--- a/gdb/d-namespace.c
+++ b/gdb/d-namespace.c
@@ -481,14 +481,12 @@ d_lookup_symbol_module (const char *scope, const char *name,
 
   /* Search for name in modules imported to this and parent
      blocks.  */
-  while (block != NULL)
+  for (auto b : block::block_and_superblocks (block))
     {
-      sym = d_lookup_symbol_imports (scope, name, block, domain);
+      sym = d_lookup_symbol_imports (scope, name, b, domain);
 
       if (sym.symbol != NULL)
 	return sym;
-
-      block = block->superblock ();
     }
 
   return {};
diff --git a/gdb/dwarf2/line-program.c b/gdb/dwarf2/line-program.c
index b9da1b4799f..227ec01aec9 100644
--- a/gdb/dwarf2/line-program.c
+++ b/gdb/dwarf2/line-program.c
@@ -373,21 +373,15 @@ dwarf_find_and_extend_inline_block_range (dwarf2_cu *cu,
      the child of a non-inline block.  This is new inline block is our
      candidate for extending.  */
   struct block *block = nullptr;
-  for (const struct block *b = it->second;
-       b != nullptr;
-       b = b->superblock ())
-    {
-      if (b->function () != nullptr && b->inlined_p ())
-	{
-	  if (b->superblock () != nullptr
-	      && b->superblock ()->function () != nullptr
-	      && !b->superblock ()->inlined_p ())
-	    {
-	      block = const_cast<struct block *> (b);
-	      break;
-	    }
-	}
-    }
+  for (auto b : block::block_and_superblocks (it->second))
+    if (b->inlined_p ()
+	&& b->superblock () != nullptr
+	&& b->superblock ()->function () != nullptr
+	&& !b->superblock ()->inlined_p ())
+      {
+	block = const_cast<struct block *> (b);
+	break;
+      }
 
   /* If we didn't find a block, or the block we found wasn't called from
      the expected LINE, then we're done.  Maybe we should try harder to
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 11c5d5214d6..be57c521a0d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -8261,13 +8261,15 @@ process_event_stop_test (struct execution_control_state *ecs)
       const struct block *prev
 	= block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
       const struct block *curr = block_for_pc (ecs->event_thread->stop_pc ());
-      while (curr != nullptr && !curr->contains (prev))
+      for (auto b : block::block_and_superblocks (curr))
 	{
-	  if (curr->inlined_p ())
+	  if (b->contains (prev))
+	    break;
+
+	  if (b->inlined_p ())
 	    depth++;
-	  else if (curr->function () != nullptr)
+	  else if (b->function () != nullptr)
 	    break;
-	  curr = curr->superblock ();
        }
       while (inline_skipped_frames (ecs->event_thread) > depth)
 	step_into_inline_frame (ecs->event_thread);
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
index a1ccd4ed0da..3aeaebffa2d 100644
--- a/gdb/inline-frame.c
+++ b/gdb/inline-frame.c
@@ -217,7 +217,7 @@ inline_frame_sniffer (const struct frame_unwind *self,
 		      void **this_cache)
 {
   CORE_ADDR this_pc;
-  const struct block *frame_block, *cur_block;
+  const struct block *frame_block;
   int depth;
   frame_info_ptr next_frame;
   struct inline_state *state = find_inline_frame_state (inferior_thread ());
@@ -230,15 +230,15 @@ inline_frame_sniffer (const struct frame_unwind *self,
   /* Calculate DEPTH, the number of inlined functions at this
      location.  */
   depth = 0;
-  cur_block = frame_block;
-  while (cur_block->superblock ())
+  for (auto cur_block : frame_block->block_and_superblocks ())
     {
+      if (cur_block->superblock () == nullptr)
+	break;
+
       if (cur_block->inlined_p ())
 	depth++;
       else if (cur_block->function () != NULL)
 	break;
-
-      cur_block = cur_block->superblock ();
     }
 
   /* Check how many inlined functions already have frames.  */
@@ -361,25 +361,22 @@ gather_inline_frames (CORE_ADDR this_pc)
     return {};
 
   std::vector<const symbol *> function_symbols;
-  while (cur_block != nullptr)
-    {
-      if (cur_block->inlined_p ())
-	{
-	  gdb_assert (cur_block->function () != nullptr);
-
-	  /* See comments in inline_frame_this_id about this use
-	     of BLOCK_ENTRY_PC.  */
-	  if (cur_block->entry_pc () == this_pc
-	      || block_starting_point_at (bv, this_pc, cur_block))
-	    function_symbols.push_back (cur_block->function ());
-	  else
-	    break;
-	}
-      else if (cur_block->function () != nullptr)
-	break;
-
-      cur_block = cur_block->superblock ();
-    }
+  auto range = block::block_and_superblocks (cur_block);
+  for (auto b = range.begin (); b != range.end (); ++b, cur_block = *b)
+    if (cur_block->inlined_p ())
+      {
+	gdb_assert (cur_block->function () != nullptr);
+
+	/* See comments in inline_frame_this_id about this use
+	   of BLOCK_ENTRY_PC.  */
+	if (cur_block->entry_pc () == this_pc
+	    || block_starting_point_at (bv, this_pc, cur_block))
+	  function_symbols.push_back (cur_block->function ());
+	else
+	  break;
+      }
+    else if (cur_block->function () != nullptr)
+      break;
 
   /* If we have a code region for which we have no function blocks,
      possibly due to bad debug, or possibly just when some debug
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 6ed4b4553d3..c393e855a91 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -1194,11 +1194,10 @@ iterate_over_file_blocks
    domain_search_flags domain,
    for_each_symbol_callback_ftype callback)
 {
-  const struct block *block;
+  const struct block *static_block
+    = symtab->compunit ()->blockvector ()->static_block ();
 
-  for (block = symtab->compunit ()->blockvector ()->static_block ();
-       block != NULL;
-       block = block->superblock ())
+  for (auto block : block::block_and_superblocks (static_block))
     current_language->for_each_symbol (block, name, domain, callback);
 }
 
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index 89374bd8a2f..f882f3add17 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -961,11 +961,10 @@ block_depth (const struct block *block)
 {
   int i = 0;
 
-  while ((block = block->superblock ()) != NULL)
-    {
-      i++;
-    }
-  return i;
+  for (auto b [[maybe_unused]]: block::block_and_superblocks (block))
+    i++;
+
+  return i - 1;
 }
 \f
 
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 3c10e1fd750..d8e4e6375d9 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2181,14 +2181,17 @@ lookup_local_symbol (const char *name,
 
   const char *scope = block->scope ();
 
-  while (!block->is_global_block () && !block->is_static_block ())
+  for (auto b : block->block_and_superblocks ())
     {
+      if (b->is_global_block () || b->is_static_block ())
+	break;
+
       struct symbol *sym = lookup_symbol_in_block (name, match_type,
-						   block, domain);
+						   b, domain);
       if (sym != NULL)
-	return (struct block_symbol) {sym, block};
+	return (struct block_symbol) {sym, b};
 
-      struct symbol *function = block->function ();
+      struct symbol *function = b->function ();
       if (function != nullptr && function->is_template_function ())
 	{
 	  struct template_symbol *templ = (struct template_symbol *) function;
@@ -2196,17 +2199,16 @@ lookup_local_symbol (const char *name,
 				    templ->n_template_arguments,
 				    templ->template_arguments);
 	  if (sym != nullptr)
-	    return (struct block_symbol) {sym, block};
+	    return (struct block_symbol) {sym, b};
 	}
 
       struct block_symbol blocksym
-	= langdef->lookup_symbol_local (scope, name, block, domain);
+	= langdef->lookup_symbol_local (scope, name, b, domain);
       if (blocksym.symbol != nullptr)
 	return blocksym;
 
-      if (block->inlined_p ())
+      if (b->inlined_p ())
 	break;
-      block = block->superblock ();
     }
 
   /* We've reached the end of the function without finding a result.  */
@@ -3829,13 +3831,17 @@ skip_prologue_sal (struct symtab_and_line *sal)
      use the call site of the function instead.  */
   const block *function_block = nullptr;
 
-  for (const block *b = block_for_pc_sect (sal->pc, sal->section);
-       b != nullptr;
-       b = b->superblock ())
-    if (b->function () != NULL && b->inlined_p ())
-      function_block = b;
-    else if (b->function () != NULL)
-      break;
+  const block *pc_block = block_for_pc_sect (sal->pc, sal->section);
+  for (auto b: block::block_and_superblocks (pc_block))
+    {
+      if (b->function () == nullptr)
+	continue;
+
+      if (b->inlined_p ())
+	function_block = b;
+      else
+	break;
+    }
 
   if (function_block != NULL
       && function_block->function ()->line () != 0)
@@ -3929,7 +3935,8 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr)
 	     same function, not something inlined.  If it's inlined,
 	     then there is no point comparing the line numbers.  */
 	  bl = block_for_pc (prologue_sal.end);
-	  while (bl)
+	  auto range = block::block_and_superblocks (bl);
+	  for (auto b = range.begin (); b != range.end (); ++b, bl = *b)
 	    {
 	      if (bl->inlined_p ())
 		break;
@@ -3938,7 +3945,6 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr)
 		  bl = NULL;
 		  break;
 		}
-	      bl = bl->superblock ();
 	    }
 	  if (bl != NULL)
 	    break;
@@ -5868,7 +5874,7 @@ default_collect_symbol_completion_matches_break_on
      frees them.  I'm not going to worry about this; hopefully there
      won't be that many.  */
 
-  const struct block *b;
+  const struct block *selected_block;
   const struct block *surrounding_static_block, *surrounding_global_block;
   /* The symbol we are completing on.  Points in same buffer as text.  */
   const char *sym_text;
@@ -5977,12 +5983,17 @@ default_collect_symbol_completion_matches_break_on
      this places which match our text string.  Only complete on types
      visible from current context.  */
 
-  b = get_selected_block (0);
-  surrounding_static_block = b == nullptr ? nullptr : b->static_block ();
-  surrounding_global_block = b == nullptr ? nullptr : b->global_block ();
+  selected_block = get_selected_block (0);
+  surrounding_static_block
+    = selected_block == nullptr ? nullptr : selected_block->static_block ();
+  surrounding_global_block
+    = selected_block == nullptr ? nullptr : selected_block->global_block ();
   if (surrounding_static_block != NULL)
-    while (b != surrounding_static_block)
+    for (auto b : block::block_and_superblocks (selected_block))
       {
+	if (b == surrounding_static_block)
+	  break;
+
 	QUIT;
 
 	for (struct symbol *sym : block_iterator_range (b))
@@ -6003,9 +6014,8 @@ default_collect_symbol_completion_matches_break_on
 	/* Stop when we encounter an enclosing function.  Do not stop for
 	   non-inlined functions - the locals of the enclosing function
 	   are in scope for a nested function.  */
-	if (b->function () != NULL && b->inlined_p ())
+	if (b->inlined_p ())
 	  break;
-	b = b->superblock ();
       }
 
   /* Add fields from the file's types; symbols will be added below.  */
-- 
2.51.0


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

* [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (7 preceding siblings ...)
  2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
  2026-05-01 12:45 ` [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn Tom de Vries
  2026-06-09 12:40 ` [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
  To: gdb-patches

Add a function block::block_and_superblocks_in_fn that can be used to
transform:
...
  while (block != NULL)
    {
      ...
      if (block->function () != nullptr)
        break;
      block = block->superblock ();
    }
...
into:
...
  for (auto b : block::block_and_superblocks_in_fn (block))
    {
      ...
    }
...

In fact the new loop is somewhat stricter, because it systematically ignores
the static and global blocks.

This means that the transformation is not strictly semantics-preserving.  I'm
still on the fence about whether this is a good idea.

My assumption here is that these loops are written assuming a well-formed
block hierarchy:
...
global block <- static block <- function block <- in-function block
...
as well as assuming that the starting block is not the static or global block.

And for such loops, the stricter static/global blocks skipping behavior
doesn't matter.
---
 gdb/block.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/gdb/block.h b/gdb/block.h
index ff5203ae4c6..c39425185aa 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -127,7 +127,42 @@ struct block : public allocate_on_obstack<block>
     }
   };
 
+  /* Variant of next_iterator using the superblock field instead of next.  */
+  struct function_block_iterator
+    : base_next_iterator<const block, function_block_iterator>
+  {
+    typedef function_block_iterator self_type;
+
+    explicit function_block_iterator (value_type item)
+      : base_next_iterator (item->is_global_block () || item->is_static_block ()
+			    ? nullptr : item)
+    {
+    }
+
+    function_block_iterator () = default;
+
+    value_type next ()
+    {
+      if (m_item->function () != nullptr)
+	return nullptr;
+
+      value_type next = m_item->superblock ();
+      if (next->is_global_block () || next->is_static_block ())
+	{
+	  /* This shouldn't be reachable in well-formed block hierarchies, given
+	     that we avoid global and static block in the constructor, and
+	     stop iterating when encountering a function.  But let's try to be
+	     robust and ensure that this iterator never points to a static or
+	     global block.  */
+	  return nullptr;
+	}
+
+      return next;
+    }
+  };
+
   using superblock_range = iterator_range<superblock_iterator>;
+  using function_block_range = iterator_range<function_block_iterator>;
 
   /* Return this block's start address.  */
   CORE_ADDR start () const
@@ -352,6 +387,27 @@ struct block : public allocate_on_obstack<block>
     return b->block_and_superblocks ();
   }
 
+  /* Return a range adapter that iterates over this block and its
+     superblocks in the same function.  */
+
+  function_block_range block_and_superblocks_in_fn () const
+  {
+    function_block_range::iterator begin (this);
+
+    return function_block_range (std::move (begin));
+  }
+
+  /* Return a range adapter that iterates over B and its superblocks in the
+     same function.  */
+
+  static function_block_range block_and_superblocks_in_fn (const block *b)
+  {
+    if (b == nullptr)
+      return function_block_range ();
+
+    return b->block_and_superblocks_in_fn ();
+  }
+
   /* Return true if block A is lexically nested within this block, or
      if A and this block have the same pc range.  Return false
      otherwise.  If ALLOW_NESTED is true, then block A is considered
-- 
2.51.0


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

* [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (8 preceding siblings ...)
  2026-05-01 12:45 ` [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn Tom de Vries
@ 2026-05-01 12:45 ` Tom de Vries
  2026-06-09 12:40 ` [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-05-01 12:45 UTC (permalink / raw)
  To: gdb-patches

Add uses of block::block_and_superblocks_in_fn.
---
 gdb/ada-lang.c                  |  43 ++++-----
 gdb/compile/compile-c-symbols.c |  10 +--
 gdb/f-valprint.c                |  19 ++--
 gdb/mi/mi-cmd-stack.c           | 155 +++++++++++++++-----------------
 gdb/python/py-unwind.c          |   2 +-
 gdb/stack.c                     |  15 ++--
 gdb/symtab.c                    |  11 +--
 gdb/tracepoint.c                |   9 +-
 8 files changed, 114 insertions(+), 150 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 6eb928b445d..400760be1ba 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13118,32 +13118,27 @@ ada_add_exceptions_from_frame (compiled_regex *preg,
 			       const frame_info_ptr &frame,
 			       std::vector<ada_exc_info> *exceptions)
 {
-  const struct block *block = get_frame_block (frame, 0);
+  const struct block *frame_block = get_frame_block (frame, 0);
 
-  while (block != 0)
-    {
-      for (struct symbol *sym : block_iterator_range (block))
-	{
-	  switch (sym->loc_class ())
-	    {
-	    case LOC_TYPEDEF:
-	    case LOC_BLOCK:
-	    case LOC_CONST:
-	      break;
-	    default:
-	      if (ada_is_exception_sym (sym))
-		{
-		  struct ada_exc_info info = {sym->print_name (),
-					      sym->value_address ()};
+  for (auto block : block::block_and_superblocks_in_fn (frame_block))
+    for (struct symbol *sym : block_iterator_range (block))
+      {
+	switch (sym->loc_class ())
+	  {
+	  case LOC_TYPEDEF:
+	  case LOC_BLOCK:
+	  case LOC_CONST:
+	    break;
+	  default:
+	    if (ada_is_exception_sym (sym))
+	      {
+		struct ada_exc_info info = {sym->print_name (),
+					    sym->value_address ()};
 
-		  exceptions->push_back (info);
-		}
-	    }
-	}
-      if (block->function () != NULL)
-	break;
-      block = block->superblock ();
-    }
+		exceptions->push_back (info);
+	      }
+	  }
+      }
 }
 
 /* Add all exceptions defined globally whose name name match
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index dc0487d8f82..da8c6719fe5 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -588,20 +588,14 @@ generate_c_for_variable_locations (compile_instance *compiler,
      reality of shadowing.  */
   gdb::unordered_set<std::string_view> symset;
 
-  while (1)
+  for (auto b : block->block_and_superblocks_in_fn ())
     {
       /* Iterate over symbols in this block, generating code to
 	 compute the location of each local variable.  */
-      for (struct symbol *sym : block_iterator_range (block))
+      for (struct symbol *sym : block_iterator_range (b))
 	if (symset.insert (sym->natural_name ()).second)
 	  generate_c_for_for_one_variable (compiler, stream, gdbarch,
 					   registers_used, pc, sym);
-
-      /* If we just finished the outermost block of a function, we're
-	 done.  */
-      if (block->function () != NULL)
-	break;
-      block = block->superblock ();
     }
 
   return registers_used;
diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c
index 13921c03a48..44b24d788d3 100644
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -682,7 +682,7 @@ static void
 info_common_command (const char *comname, int from_tty)
 {
   frame_info_ptr fi;
-  const struct block *block;
+  const struct block *frame_block;
   int values_printed = 0;
 
   /* We have been told to display the contents of F77 COMMON
@@ -695,22 +695,17 @@ info_common_command (const char *comname, int from_tty)
   /* The following is generally ripped off from stack.c's routine
      print_frame_info().  */
 
-  block = get_frame_block (fi, 0);
-  if (block == NULL)
+  frame_block = get_frame_block (fi, 0);
+  if (frame_block == nullptr)
     {
       gdb_printf (_("No symbol table info available.\n"));
       return;
     }
 
-  while (block)
-    {
-      info_common_command_for_block (block, comname, &values_printed);
-      /* After handling the function's top-level block, stop.  Don't
-	 continue to its superblock, the block of per-file symbols.  */
-      if (block->function ())
-	break;
-      block = block->superblock ();
-    }
+  /* After handling the function's top-level block, stop.  Don't
+     continue to its superblock, the block of per-file symbols.  */
+  for (auto block : block::block_and_superblocks_in_fn (frame_block))
+    info_common_command_for_block (block, comname, &values_printed);
 
   if (!values_printed)
     {
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index f2a4b3044b0..0f46033c9b4 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -573,11 +573,11 @@ list_args_or_locals (const frame_print_options &fp_opts,
 		     enum what_to_list what, enum print_values values,
 		     const frame_info_ptr &fi, int skip_unavailable)
 {
-  const struct block *block;
+  const struct block *frame_block;
   const char *name_of_result;
   struct ui_out *uiout = current_uiout;
 
-  block = get_frame_block (fi, 0);
+  frame_block = get_frame_block (fi, 0);
 
   switch (what)
     {
@@ -596,88 +596,81 @@ list_args_or_locals (const frame_print_options &fp_opts,
 
   ui_out_emit_list list_emitter (uiout, name_of_result);
 
-  while (block != 0)
-    {
-      for (struct symbol *sym : block_iterator_range (block))
-	{
-	  int print_me = 0;
-
-	  switch (sym->loc_class ())
-	    {
-	    default:
-	    case LOC_UNDEF:	/* catches errors        */
-	    case LOC_CONST:	/* constant              */
-	    case LOC_TYPEDEF:	/* local typedef         */
-	    case LOC_LABEL:	/* local label           */
-	    case LOC_BLOCK:	/* local function        */
-	    case LOC_CONST_BYTES:	/* loc. byte seq.        */
-	    case LOC_UNRESOLVED:	/* unresolved static     */
-	    case LOC_OPTIMIZED_OUT:	/* optimized out         */
-	      print_me = 0;
-	      break;
+  for (auto block : block::block_and_superblocks_in_fn (frame_block))
+    for (struct symbol *sym : block_iterator_range (block))
+      {
+	int print_me = 0;
+
+	switch (sym->loc_class ())
+	  {
+	  default:
+	  case LOC_UNDEF:		/* catches errors	 */
+	  case LOC_CONST:		/* constant		 */
+	  case LOC_TYPEDEF:		/* local typedef	 */
+	  case LOC_LABEL:		/* local label		 */
+	  case LOC_BLOCK:		/* local function	 */
+	  case LOC_CONST_BYTES:		/* loc. byte seq.	 */
+	  case LOC_UNRESOLVED:		/* unresolved static	 */
+	  case LOC_OPTIMIZED_OUT:	/* optimized out	 */
+	    print_me = 0;
+	    break;
 
-	    case LOC_ARG:	/* argument              */
-	    case LOC_REF_ARG:	/* reference arg         */
-	    case LOC_REGPARM_ADDR:	/* indirect register arg */
-	    case LOC_LOCAL:	/* stack local           */
-	    case LOC_STATIC:	/* static                */
-	    case LOC_REGISTER:	/* register              */
-	    case LOC_COMPUTED:	/* computed location     */
-	      if (what == all)
-		print_me = 1;
-	      else if (what == locals)
-		print_me = !sym->is_argument ();
-	      else
-		print_me = sym->is_argument ();
-	      break;
-	    }
-	  if (print_me)
-	    {
-	      struct symbol *sym2;
-	      struct frame_arg arg, entryarg;
-
-	      if (sym->is_argument ())
-		sym2 = (lookup_symbol_search_name
-			(sym->search_name (),
-			 block, SEARCH_VAR_DOMAIN).symbol);
-	      else
-		sym2 = sym;
-	      gdb_assert (sym2 != NULL);
-
-	      arg.sym = sym2;
-	      arg.entry_kind = print_entry_values_no;
-	      entryarg.sym = sym2;
-	      entryarg.entry_kind = print_entry_values_no;
-
-	      switch (values)
-		{
-		case PRINT_SIMPLE_VALUES:
-		  if (!mi_simple_type_p (sym2->type ()))
-		    break;
-		  [[fallthrough]];
-
-		case PRINT_ALL_VALUES:
-		  if (sym->is_argument ())
-		    read_frame_arg (fp_opts, sym2, fi, &arg, &entryarg);
-		  else
-		    read_frame_local (sym2, fi, &arg);
+	  case LOC_ARG:			/* argument		 */
+	  case LOC_REF_ARG:		/* reference arg	 */
+	  case LOC_REGPARM_ADDR:	/* indirect register arg */
+	  case LOC_LOCAL:		/* stack local		 */
+	  case LOC_STATIC:		/* static		 */
+	  case LOC_REGISTER:		/* register		 */
+	  case LOC_COMPUTED:		/* computed location	 */
+	    if (what == all)
+	      print_me = 1;
+	    else if (what == locals)
+	      print_me = !sym->is_argument ();
+	    else
+	      print_me = sym->is_argument ();
+	    break;
+	  }
+	if (print_me)
+	  {
+	    struct symbol *sym2;
+	    struct frame_arg arg, entryarg;
+
+	    if (sym->is_argument ())
+	      sym2 = (lookup_symbol_search_name
+		      (sym->search_name (),
+		       block, SEARCH_VAR_DOMAIN).symbol);
+	    else
+	      sym2 = sym;
+	    gdb_assert (sym2 != nullptr);
+
+	    arg.sym = sym2;
+	    arg.entry_kind = print_entry_values_no;
+	    entryarg.sym = sym2;
+	    entryarg.entry_kind = print_entry_values_no;
+
+	    switch (values)
+	      {
+	      case PRINT_SIMPLE_VALUES:
+		if (!mi_simple_type_p (sym2->type ()))
 		  break;
-		}
-
-	      if (arg.entry_kind != print_entry_values_only)
-		list_arg_or_local (&arg, what, values, skip_unavailable,
-				   fp_opts);
-	      if (entryarg.entry_kind != print_entry_values_no)
-		list_arg_or_local (&entryarg, what, values, skip_unavailable,
-				   fp_opts);
-	    }
-	}
+		[[fallthrough]];
 
-      if (block->function ())
-	break;
-      else
-	block = block->superblock ();
-    }
+	      case PRINT_ALL_VALUES:
+		if (sym->is_argument ())
+		  read_frame_arg (fp_opts, sym2, fi, &arg, &entryarg);
+		else
+		  read_frame_local (sym2, fi, &arg);
+		break;
+	      }
+
+	    if (arg.entry_kind != print_entry_values_only)
+	      list_arg_or_local (&arg, what, values, skip_unavailable,
+				 fp_opts);
+	    if (entryarg.entry_kind != print_entry_values_no)
+	      list_arg_or_local (&entryarg, what, values, skip_unavailable,
+				 fp_opts);
+	  }
+      }
 }
 
 /* Read a frame specification from FRAME_EXP and return the selected frame.
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index 6dc5e11cf87..cb19496d46b 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -635,7 +635,7 @@ pending_framepy_block (PyObject *self, PyObject *args)
   PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
 
   frame_info_ptr frame = pending_frame->frame_info;
-  const struct block *block = nullptr, *fn_block;
+  const struct block *block = nullptr;
 
   try
     {
diff --git a/gdb/stack.c b/gdb/stack.c
index 6fcc26417e2..e9a01d16a3b 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2232,16 +2232,11 @@ void
 iterate_over_block_local_vars (const struct block *block,
 			       iterate_over_block_arg_local_vars_cb cb)
 {
-  while (block)
-    {
-      iterate_over_block_locals (block, cb);
-      /* After handling the function's top-level block, stop.  Don't
-	 continue to its superblock, the block of per-file
-	 symbols.  */
-      if (block->function ())
-	break;
-      block = block->superblock ();
-    }
+  /* After handling the function's top-level block, stop.  Don't
+     continue to its superblock, the block of per-file
+     symbols.  */
+  for (auto b : block::block_and_superblocks_in_fn (block))
+    iterate_over_block_locals (b, cb);
 }
 
 /* Data to be passed around in the calls to the locals and args
diff --git a/gdb/symtab.c b/gdb/symtab.c
index d8e4e6375d9..9836a7abb38 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2002,22 +2002,19 @@ lookup_language_this (const struct language_defn *lang,
   lookup_name_info this_name (lang->name_of_this (),
 			      symbol_name_match_type::SEARCH_NAME);
 
-  while (block)
+  for (auto b : block::block_and_superblocks_in_fn (block))
     {
       struct symbol *sym;
 
-      sym = block_lookup_symbol (block, this_name, SEARCH_VFT);
+      sym = block_lookup_symbol (b, this_name, SEARCH_VFT);
       if (sym != NULL)
 	{
 	  symbol_lookup_debug_printf_v
 	    ("lookup_language_this (...) = %s (%s, block %s)",
 	     sym->print_name (), host_address_to_string (sym),
-	     host_address_to_string (block));
-	  return (struct block_symbol) {sym, block};
+	     host_address_to_string (b));
+	  return (struct block_symbol) {sym, b};
 	}
-      if (block->function ())
-	break;
-      block = block->superblock ();
     }
 
   symbol_lookup_debug_printf_v ("lookup_language_this (...) = NULL");
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 7f078684b14..5608f81211a 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2456,7 +2456,6 @@ tfind_outside_command (const char *args, int from_tty)
 static void
 info_scope_command (const char *args_in, int from_tty)
 {
-  const struct block *block;
   const char *symname;
   const char *save_args = args_in;
   int j, count = 0;
@@ -2481,9 +2480,9 @@ info_scope_command (const char *args_in, int from_tty)
 
   /* Resolve line numbers to PC.  */
   resolve_sal_pc (&sals[0]);
-  block = block_for_pc (sals[0].pc);
+  const struct block *pc_block = block_for_pc (sals[0].pc);
 
-  while (block != 0)
+  for (auto block : block::block_and_superblocks_in_fn (pc_block))
     {
       QUIT;			/* Allow user to bail out with ^C.  */
       for (struct symbol *sym : block_iterator_range (block))
@@ -2607,10 +2606,6 @@ info_scope_command (const char *args_in, int from_tty)
 	      gdb_printf (", length %s.\n", pulongest (t->length ()));
 	    }
 	}
-      if (block->function ())
-	break;
-      else
-	block = block->superblock ();
     }
   if (count <= 0)
     gdb_printf ("Scope for %s contains no locals or arguments.\n",
-- 
2.51.0


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

* Re: [PATCH 06/10] [gdbsupport] Factor out base_next_iterator
  2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
@ 2026-05-08 19:17   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2026-05-08 19:17 UTC (permalink / raw)
  To: Tom de Vries; +Cc: gdb-patches

>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:

Tom> +    m_item = static_cast<D *>(this)->next ();

Space before paren.

Tom

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

* Re: [PATCH 08/10] [gdb] Use block::block_and_superblocks
  2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
@ 2026-05-08 19:41   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2026-05-08 19:41 UTC (permalink / raw)
  To: Tom de Vries; +Cc: gdb-patches

>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:

Tom> diff --git a/gdb/blockframe.c b/gdb/blockframe.c
Tom> index 8aafa6ffe57..5c981748cbc 100644
Tom> --- a/gdb/blockframe.c
Tom> +++ b/gdb/blockframe.c
Tom> @@ -69,13 +69,14 @@ get_frame_block (const frame_info_ptr &frame, CORE_ADDR *addr_in_block)
 
Tom>    inline_count = frame_inlined_callees (frame);
 
Tom> -  while (inline_count > 0)
Tom> +  auto range = bl->block_and_superblocks ();
Tom> +  for (auto b = range.begin (); b != range.end (); ++b, bl = *b)
Tom>      {
Tom> -      if (bl->inlined_p ())
Tom> -	inline_count--;
Tom> +      if (inline_count <= 0)
Tom> +	break;
 
Tom> -      bl = bl->superblock ();
Tom> -      gdb_assert (bl != NULL);
Tom> +      if ((*b)->inlined_p ())
Tom> +	inline_count--;
Tom>      }

Tom>    return bl;

I think this particular change is less clear than the code it replaces.

Tom> diff --git a/gdb/dwarf2/line-program.c b/gdb/dwarf2/line-program.c
Tom> index b9da1b4799f..227ec01aec9 100644
Tom> --- a/gdb/dwarf2/line-program.c
Tom> +++ b/gdb/dwarf2/line-program.c
Tom> @@ -373,21 +373,15 @@ dwarf_find_and_extend_inline_block_range (dwarf2_cu *cu,
Tom>       the child of a non-inline block.  This is new inline block is our
Tom>       candidate for extending.  */
Tom>    struct block *block = nullptr;
Tom> -  for (const struct block *b = it->second;
Tom> -       b != nullptr;
Tom> -       b = b->superblock ())
Tom> -    {
Tom> -      if (b->function () != nullptr && b->inlined_p ())
Tom> -	{
Tom> -	  if (b->superblock () != nullptr
Tom> -	      && b->superblock ()->function () != nullptr
Tom> -	      && !b->superblock ()->inlined_p ())
Tom> -	    {
Tom> -	      block = const_cast<struct block *> (b);
Tom> -	      break;
Tom> -	    }
Tom> -	}
Tom> -    }
Tom> +  for (auto b : block::block_and_superblocks (it->second))
Tom> +    if (b->inlined_p ()
Tom> +	&& b->superblock () != nullptr
Tom> +	&& b->superblock ()->function () != nullptr
Tom> +	&& !b->superblock ()->inlined_p ())
Tom> +      {
Tom> +	block = const_cast<struct block *> (b);
Tom> +	break;
Tom> +      }

It took me a while to figure out why you removed the check of
'function', but it's because inlined_p already does this check.

It's helpful to call out this kind of change or to put it in a separate
patch.

Tom> --- a/gdb/infrun.c
Tom> +++ b/gdb/infrun.c
Tom> @@ -8261,13 +8261,15 @@ process_event_stop_test (struct execution_control_state *ecs)
Tom>        const struct block *prev
Tom>  	= block_for_pc (ecs->event_thread->control.step_frame_id.code_addr);
Tom>        const struct block *curr = block_for_pc (ecs->event_thread->stop_pc ());
Tom> -      while (curr != nullptr && !curr->contains (prev))
Tom> +      for (auto b : block::block_and_superblocks (curr))
Tom>  	{

This code would be clearer if 'curr' were eliminated entirely.
In this case I had to go see if it was used after the loop.

Tom> +  auto range = block::block_and_superblocks (cur_block);
Tom> +  for (auto b = range.begin (); b != range.end (); ++b, cur_block = *b)

This is another case where the result is harder to reason about that the
earlier code.

Maybe it could be salvaged somehow by assigning at the breaks, not sure.

Tom> diff --git a/gdb/symmisc.c b/gdb/symmisc.c
Tom> index 89374bd8a2f..f882f3add17 100644
Tom> --- a/gdb/symmisc.c
Tom> +++ b/gdb/symmisc.c
Tom> @@ -961,11 +961,10 @@ block_depth (const struct block *block)
Tom>  {
Tom>    int i = 0;
 
Tom> -  while ((block = block->superblock ()) != NULL)
Tom> -    {
Tom> -      i++;
Tom> -    }
Tom> -  return i;
Tom> +  for (auto b [[maybe_unused]]: block::block_and_superblocks (block))
Tom> +    i++;
Tom> +
Tom> +  return i - 1;

Can this just be std::count?

Also this doesn't have to handle the case where the initial block is
nullptr.

Tom> +	  auto range = block::block_and_superblocks (bl);
Tom> +	  for (auto b = range.begin (); b != range.end (); ++b, bl = *b)

Like the earlier ones.  I don't think multiple assignments like this
make it clearer or easier to work with.

Tom

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

* Re: [PATCH 00/10] [gdb] Add superblocks range loops
  2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
                   ` (9 preceding siblings ...)
  2026-05-01 12:45 ` [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn Tom de Vries
@ 2026-06-09 12:40 ` Tom de Vries
  10 siblings, 0 replies; 14+ messages in thread
From: Tom de Vries @ 2026-06-09 12:40 UTC (permalink / raw)
  To: gdb-patches

On 5/1/26 2:44 PM, Tom de Vries wrote:
>    [gdb] Add unit test for next_iterator
>    [gdbsupport] Use using instead of typedef in next_iterator

I've committed these two patches.

I had Claude Code review these, and it complained about a magic constant 
in the unit test, so I eliminated this.  The change is so trivial that 
it doesn't look worth the trouble of re-posting the patch.

Thanks,
- Tom

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

end of thread, other threads:[~2026-06-09 12:41 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-01 12:44 [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries
2026-05-01 12:44 ` [PATCH 01/10] [gdb] Use block::containing_function Tom de Vries
2026-05-01 12:44 ` [PATCH 02/10] [gdb] Factor out block::containing_function_block Tom de Vries
2026-05-01 12:44 ` [PATCH 03/10] [gdb] Use block::containing_function_block Tom de Vries
2026-05-01 12:44 ` [PATCH 04/10] [gdb] Add unit test for next_iterator Tom de Vries
2026-05-01 12:44 ` [PATCH 05/10] [gdbsupport] Use using instead of typedef in next_iterator Tom de Vries
2026-05-01 12:45 ` [PATCH 06/10] [gdbsupport] Factor out base_next_iterator Tom de Vries
2026-05-08 19:17   ` Tom Tromey
2026-05-01 12:45 ` [PATCH 07/10] [gdb] Add block::block_and_superblocks Tom de Vries
2026-05-01 12:45 ` [PATCH 08/10] [gdb] Use block::block_and_superblocks Tom de Vries
2026-05-08 19:41   ` Tom Tromey
2026-05-01 12:45 ` [PATCH 09/10] [gdb] Add block::block_and_superblocks_in_fn Tom de Vries
2026-05-01 12:45 ` [PATCH 10/10] [gdb] Use block::block_and_superblocks_in_fn Tom de Vries
2026-06-09 12:40 ` [PATCH 00/10] [gdb] Add superblocks range loops Tom de Vries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox