Skip to content

Commit f23bac6

Browse files
Ericson2314jicama
authored andcommitted
driver: Rework for_each_path using C++
The old C-style was cumbersome make making one responsible for manually creating and passing in two parts a closure (separate function and *_info class for closed-over variables). With C++ lambdas, we can just: - derive environment types implicitly - have fewer stray static functions Also thanks to templates we can - make the return type polymorphic, to avoid casting pointee types. Note that `struct spec_path` was *not* converted because it is used multiple times. We could still 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. Instead, I define the `operator()` explicitly. Keeping the explicit struct gives us some nice "named arguments", versus the wrapper function alternative, too. gcc/ChangeLog: * gcc.cc (for_each_path): templated, to make passing lambdas possible/easy/safe, and to have a polymorphic return type. (struct add_to_obstack_info): Deleted, lambda captures replace it. (add_to_obstack): Moved to lambda in build_search_list. (build_search_list): Has above lambda now. (struct file_at_path_info): Deleted, lambda captures replace it. (file_at_path): Moved to lambda in find_a_file. (find_a_file): Has above lambda now. (struct spec_path_info): Reamed to just struct spec_path. (struct spec_path): New name. (spec_path): Rnamed to spec_path::operator() (spec_path::operator()): New name (do_spec_1): Updated for_each_path call sites. Signed-off-by: John Ericson <git@JohnEricson.me> Reviewed-by: Jason Merrill <jason@redhat.com>
1 parent 5b85364 commit f23bac6

File tree

1 file changed

+77
-108
lines changed

1 file changed

+77
-108
lines changed

gcc/gcc.cc

Lines changed: 77 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -2774,12 +2774,12 @@ clear_failure_queue (void)
27742774
27752775
Returns the value returned by CALLBACK. */
27762776

2777-
static void *
2777+
template<typename fun>
2778+
auto *
27782779
for_each_path (const struct path_prefix *paths,
27792780
bool do_multi,
27802781
size_t extra_space,
2781-
void *(*callback) (char *, void *),
2782-
void *callback_info)
2782+
fun && callback)
27832783
{
27842784
struct prefix_list *pl;
27852785
const char *multi_dir = NULL;
@@ -2788,7 +2788,7 @@ for_each_path (const struct path_prefix *paths,
27882788
const char *multi_suffix;
27892789
const char *just_multi_suffix;
27902790
char *path = NULL;
2791-
void *ret = NULL;
2791+
decltype (callback (nullptr)) ret;
27922792
bool skip_multi_dir = false;
27932793
bool skip_multi_os_dir = false;
27942794

@@ -2839,7 +2839,7 @@ for_each_path (const struct path_prefix *paths,
28392839
if (!skip_multi_dir)
28402840
{
28412841
memcpy (path + len, multi_suffix, suffix_len + 1);
2842-
ret = callback (path, callback_info);
2842+
ret = callback (path);
28432843
if (ret)
28442844
break;
28452845
}
@@ -2850,7 +2850,7 @@ for_each_path (const struct path_prefix *paths,
28502850
&& pl->require_machine_suffix == 2)
28512851
{
28522852
memcpy (path + len, just_multi_suffix, just_suffix_len + 1);
2853-
ret = callback (path, callback_info);
2853+
ret = callback (path);
28542854
if (ret)
28552855
break;
28562856
}
@@ -2860,7 +2860,7 @@ for_each_path (const struct path_prefix *paths,
28602860
&& !pl->require_machine_suffix && multiarch_dir)
28612861
{
28622862
memcpy (path + len, multiarch_suffix, multiarch_len + 1);
2863-
ret = callback (path, callback_info);
2863+
ret = callback (path);
28642864
if (ret)
28652865
break;
28662866
}
@@ -2888,7 +2888,7 @@ for_each_path (const struct path_prefix *paths,
28882888
else
28892889
path[len] = '\0';
28902890

2891-
ret = callback (path, callback_info);
2891+
ret = callback (path);
28922892
if (ret)
28932893
break;
28942894
}
@@ -2934,31 +2934,6 @@ for_each_path (const struct path_prefix *paths,
29342934
return ret;
29352935
}
29362936

2937-
/* Callback for build_search_list. Adds path to obstack being built. */
2938-
2939-
struct add_to_obstack_info {
2940-
struct obstack *ob;
2941-
bool check_dir;
2942-
bool first_time;
2943-
};
2944-
2945-
static void *
2946-
add_to_obstack (char *path, void *data)
2947-
{
2948-
struct add_to_obstack_info *info = (struct add_to_obstack_info *) data;
2949-
2950-
if (info->check_dir && !is_directory (path))
2951-
return NULL;
2952-
2953-
if (!info->first_time)
2954-
obstack_1grow (info->ob, PATH_SEPARATOR);
2955-
2956-
obstack_grow (info->ob, path, strlen (path));
2957-
2958-
info->first_time = false;
2959-
return NULL;
2960-
}
2961-
29622937
/* Add or change the value of an environment variable, outputting the
29632938
change to standard error if in verbose mode. */
29642939
static void
@@ -2979,16 +2954,26 @@ static char *
29792954
build_search_list (const struct path_prefix *paths, const char *prefix,
29802955
bool check_dir, bool do_multi)
29812956
{
2982-
struct add_to_obstack_info info;
2983-
2984-
info.ob = &collect_obstack;
2985-
info.check_dir = check_dir;
2986-
info.first_time = true;
2957+
struct obstack *const ob = &collect_obstack;
2958+
bool first_time = true;
29872959

29882960
obstack_grow (&collect_obstack, prefix, strlen (prefix));
29892961
obstack_1grow (&collect_obstack, '=');
29902962

2991-
for_each_path (paths, do_multi, 0, add_to_obstack, &info);
2963+
/* Callback adds path to obstack being built. */
2964+
for_each_path (paths, do_multi, 0, [&](char *path) -> void*
2965+
{
2966+
if (check_dir && !is_directory (path))
2967+
return NULL;
2968+
2969+
if (!first_time)
2970+
obstack_1grow (ob, PATH_SEPARATOR);
2971+
2972+
obstack_grow (ob, path, strlen (path));
2973+
2974+
first_time = false;
2975+
return NULL;
2976+
});
29922977

29932978
obstack_1grow (&collect_obstack, '\0');
29942979
return XOBFINISH (&collect_obstack, char *);
@@ -3022,42 +3007,6 @@ access_check (const char *name, int mode)
30223007
return access (name, mode);
30233008
}
30243009

3025-
/* Callback for find_a_file. Appends the file name to the directory
3026-
path. If the resulting file exists in the right mode, return the
3027-
full pathname to the file. */
3028-
3029-
struct file_at_path_info {
3030-
const char *name;
3031-
const char *suffix;
3032-
int name_len;
3033-
int suffix_len;
3034-
int mode;
3035-
};
3036-
3037-
static void *
3038-
file_at_path (char *path, void *data)
3039-
{
3040-
struct file_at_path_info *info = (struct file_at_path_info *) data;
3041-
size_t len = strlen (path);
3042-
3043-
memcpy (path + len, info->name, info->name_len);
3044-
len += info->name_len;
3045-
3046-
/* Some systems have a suffix for executable files.
3047-
So try appending that first. */
3048-
if (info->suffix_len)
3049-
{
3050-
memcpy (path + len, info->suffix, info->suffix_len + 1);
3051-
if (access_check (path, info->mode) == 0)
3052-
return path;
3053-
}
3054-
3055-
path[len] = '\0';
3056-
if (access_check (path, info->mode) == 0)
3057-
return path;
3058-
3059-
return NULL;
3060-
}
30613010

30623011
/* Search for NAME using the prefix list PREFIXES. MODE is passed to
30633012
access to check permissions. If DO_MULTI is true, search multilib
@@ -3068,8 +3017,6 @@ static char *
30683017
find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
30693018
bool do_multi)
30703019
{
3071-
struct file_at_path_info info;
3072-
30733020
/* Find the filename in question (special case for absolute paths). */
30743021

30753022
if (IS_ABSOLUTE_PATH (name))
@@ -3080,15 +3027,38 @@ find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
30803027
return NULL;
30813028
}
30823029

3083-
info.name = name;
3084-
info.suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
3085-
info.name_len = strlen (info.name);
3086-
info.suffix_len = strlen (info.suffix);
3087-
info.mode = mode;
3030+
const char *suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
3031+
const int name_len = strlen (name);
3032+
const int suffix_len = strlen (suffix);
30883033

3089-
return (char*) for_each_path (pprefix, do_multi,
3090-
info.name_len + info.suffix_len,
3091-
file_at_path, &info);
3034+
3035+
/* Callback appends the file name to the directory path. If the
3036+
resulting file exists in the right mode, return the full pathname
3037+
to the file. */
3038+
return for_each_path (pprefix, do_multi,
3039+
name_len + suffix_len,
3040+
[=](char *path) -> char*
3041+
{
3042+
size_t len = strlen (path);
3043+
3044+
memcpy (path + len, name, name_len);
3045+
len += name_len;
3046+
3047+
/* Some systems have a suffix for executable files.
3048+
So try appending that first. */
3049+
if (suffix_len)
3050+
{
3051+
memcpy (path + len, suffix, suffix_len + 1);
3052+
if (access_check (path, mode) == 0)
3053+
return path;
3054+
}
3055+
3056+
path[len] = '\0';
3057+
if (access_check (path, mode) == 0)
3058+
return path;
3059+
3060+
return NULL;
3061+
});
30923062
}
30933063

30943064
/* Specialization of find_a_file for programs that also takes into account
@@ -6008,49 +5978,50 @@ do_self_spec (const char *spec)
60085978

60095979
/* Callback for processing %D and %I specs. */
60105980

6011-
struct spec_path_info {
5981+
struct spec_path {
60125982
const char *option;
60135983
const char *append;
60145984
size_t append_len;
60155985
bool omit_relative;
60165986
bool separate_options;
60175987
bool realpaths;
5988+
5989+
void *operator() (char *path);
60185990
};
60195991

6020-
static void *
6021-
spec_path (char *path, void *data)
5992+
void *
5993+
spec_path::operator() (char *path)
60225994
{
6023-
struct spec_path_info *info = (struct spec_path_info *) data;
60245995
size_t len = 0;
60255996
char save = 0;
60265997

60275998
/* The path must exist; we want to resolve it to the realpath so that this
60285999
can be embedded as a runpath. */
6029-
if (info->realpaths)
6000+
if (realpaths)
60306001
path = lrealpath (path);
60316002

60326003
/* However, if we failed to resolve it - perhaps because there was a bogus
60336004
-B option on the command line, then punt on this entry. */
60346005
if (!path)
60356006
return NULL;
60366007

6037-
if (info->omit_relative && !IS_ABSOLUTE_PATH (path))
6008+
if (omit_relative && !IS_ABSOLUTE_PATH (path))
60386009
return NULL;
60396010

6040-
if (info->append_len != 0)
6011+
if (append_len != 0)
60416012
{
60426013
len = strlen (path);
6043-
memcpy (path + len, info->append, info->append_len + 1);
6014+
memcpy (path + len, append, append_len + 1);
60446015
}
60456016

60466017
if (!is_directory (path))
60476018
return NULL;
60486019

6049-
do_spec_1 (info->option, 1, NULL);
6050-
if (info->separate_options)
6020+
do_spec_1 (option, 1, NULL);
6021+
if (separate_options)
60516022
do_spec_1 (" ", 0, NULL);
60526023

6053-
if (info->append_len == 0)
6024+
if (append_len == 0)
60546025
{
60556026
len = strlen (path);
60566027
save = path[len - 1];
@@ -6062,7 +6033,7 @@ spec_path (char *path, void *data)
60626033
do_spec_1 (" ", 0, NULL);
60636034

60646035
/* Must not damage the original path. */
6065-
if (info->append_len == 0)
6036+
if (append_len == 0)
60666037
path[len - 1] = save;
60676038

60686039
return NULL;
@@ -6250,7 +6221,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
62506221
that we search for startfiles. */
62516222
case 'D':
62526223
{
6253-
struct spec_path_info info;
6224+
struct spec_path info;
62546225

62556226
info.option = "-L";
62566227
info.append_len = 0;
@@ -6267,13 +6238,13 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
62676238
info.separate_options = false;
62686239
info.realpaths = false;
62696240

6270-
for_each_path (&startfile_prefixes, true, 0, spec_path, &info);
6241+
for_each_path (&startfile_prefixes, true, 0, info);
62716242
}
62726243
break;
62736244

62746245
case 'P':
62756246
{
6276-
struct spec_path_info info;
6247+
struct spec_path info;
62776248

62786249
info.option = RUNPATH_OPTION;
62796250
info.append_len = 0;
@@ -6282,7 +6253,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
62826253
/* We want to embed the actual paths that have the libraries. */
62836254
info.realpaths = true;
62846255

6285-
for_each_path (&startfile_prefixes, true, 0, spec_path, &info);
6256+
for_each_path (&startfile_prefixes, true, 0, info);
62866257
}
62876258
break;
62886259

@@ -6561,7 +6532,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
65616532

65626533
case 'I':
65636534
{
6564-
struct spec_path_info info;
6535+
struct spec_path info;
65656536

65666537
if (multilib_dir)
65676538
{
@@ -6609,8 +6580,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
66096580
info.separate_options = true;
66106581
info.realpaths = false;
66116582

6612-
for_each_path (&include_prefixes, false, info.append_len,
6613-
spec_path, &info);
6583+
for_each_path (&include_prefixes, false, info.append_len, info);
66146584

66156585
info.append = "include-fixed";
66166586
if (*sysroot_hdrs_suffix_spec)
@@ -6623,14 +6593,13 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
66236593
info.append = concat (info.append, dir_separator_str,
66246594
multiarch_dir, NULL);
66256595
info.append_len = strlen (info.append);
6626-
for_each_path (&include_prefixes, false, info.append_len,
6627-
spec_path, &info);
6596+
for_each_path (&include_prefixes, false,
6597+
info.append_len, info);
66286598

66296599
info.append = "include-fixed";
66306600
}
66316601
info.append_len = strlen (info.append);
6632-
for_each_path (&include_prefixes, false, info.append_len,
6633-
spec_path, &info);
6602+
for_each_path (&include_prefixes, false, info.append_len, info);
66346603
}
66356604
break;
66366605

0 commit comments

Comments
 (0)