On 8/21/25 1:01 AM, John Ericson wrote:
A follow-up from "driver: Rework for_each_path using C++"

These types are, for all intents and purposes, single-use closure
environment types. It is much more ergonomic to juse use lambdas for
this.

On IRC there was concern about static dispatch and compile times with
lambdas, but I have kept the class hierarchy and virtual methods from
the previous commit that keeps `find_within_paths::for_each_path`
untemplated, and I believe that add addresses the issue.

Note that `struct spec_path` was *not* converted because it is used
multiple times. We could stil convert to a lambda, but we would want to
put the for_each_path call with that lambda inside a separate function
anyways, to support the multiple callers. Unlike the other two
refactors, it is not clear that this one would make anything shorter.

gcc/ChangeLog:

        * gcc.cc (struct add_to_obstack): Gone, lambda capture list
        replaces it.
        (struct file_at_path): Gone, lambda capture list replaces it.
        (add_to_obstack::callback): Moved to lambda in
        build_search_list.
        (file_at_path::callback): Moved to lambda in fine_a_file.
        (for_each_path): New tiny templated wrapper for lambda
        (build_search_list): Use for_each_path with lambda.
        (find_a_file): Use for_each_path with lambda.

Signed-off-by: John Ericson <g...@johnericson.me>
---
  gcc/gcc.cc | 142 +++++++++++++++++++++++++----------------------------
  1 file changed, 66 insertions(+), 76 deletions(-)

diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index d43a347d120..94d9f760da6 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -2944,30 +2944,28 @@ find_within_paths::for_each_path (const struct 
path_prefix *paths,
    return ret;
  }
-/* Callback for build_search_list. Adds path to obstack being built. */
-
-struct add_to_obstack : find_within_paths {
-  struct obstack *ob;
-  bool check_dir;
-  bool first_time;
-
-private:
-  void *callback (char *path) override;
-};
-
-void *
-add_to_obstack::callback (char *path)
+/* This is an adapter for using a lambda.  It is separate from
+   find_within_paths::for_each_path in order that the main body of the
+   function (that function) *not* be template-specialised, and just this
+   tiny wrapper is instead.  */
+template<typename fun>
+static void *
+for_each_path (const struct path_prefix *paths,
+              bool do_multi,
+              size_t extra_space,
+              fun && callback)
  {
-  if (check_dir && !is_directory (path))
-    return NULL;
-
-  if (!first_time)
-    obstack_1grow (ob, PATH_SEPARATOR);
-
-  obstack_grow (ob, path, strlen (path));
-
-  first_time = false;
-  return NULL;
+  struct adapter : find_within_paths {
+    fun cb;
+    adapter(fun && cb) : cb{cb} {}
+  private:
+    void *callback (char *path) override
+    {
+      return cb(path);
+    }
+  };
+  adapter a{std::move(callback)};
+  return a.for_each_path(paths, do_multi, extra_space);
  }
/* Add or change the value of an environment variable, outputting the
@@ -2990,16 +2988,25 @@ static char *
  build_search_list (const struct path_prefix *paths, const char *prefix,
                   bool check_dir, bool do_multi)
  {
-  struct add_to_obstack info;
-
-  info.ob = &collect_obstack;
-  info.check_dir = check_dir;
-  info.first_time = true;
+  struct obstack *const ob = &collect_obstack;
+  bool first_time = true;
obstack_grow (&collect_obstack, prefix, strlen (prefix));
    obstack_1grow (&collect_obstack, '=');
- info.for_each_path (paths, do_multi, 0);
+  /* Callback adds path to obstack being built.  */
+  for_each_path (paths, do_multi, 0, [ob, &first_time, check_dir](char *path) 
-> void* {

Line too long; the simplest fix would be to simplify the capture list to [&]. Also, the { should be on the next line, per
https://gcc.gnu.org/codingconventions.html#Lambda_Form

@@ -3093,14 +3060,37 @@ find_a_file (const struct path_prefix *pprefix, const 
char *name, int mode,
        return NULL;
      }
- info.name = name;
-  info.suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
-  info.name_len = strlen (info.name);
-  info.suffix_len = strlen (info.suffix);
-  info.mode = mode;
+  const char *suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
+  const int name_len = strlen (name);
+  const int suffix_len = strlen (suffix);
+
+
+  /* Callback appends the file name to the directory path.  If the
+     resulting file exists in the right mode, return the full pathname
+     to the file.  */
+  return (char*) for_each_path (pprefix, do_multi,
+                               name_len + suffix_len,
+                               [name, suffix, suffix_len, name_len, mode](char 
*path) -> void* {

Likewise.  Or optionally [=] in this case.

Jason

Reply via email to