Declaration of non-local variable in 'for' loop
NullPointerHub opened this issue · comments
When using hashmap_foreach、hashmap_foreach_safe, the compiler gives a warning,
Declaration of non-local variable in 'for' loop。
clang cannot compile project because of this.
error: declaration of non-local variable in 'for' loop
hashmap_foreach(key, b, &map) {
^
hashmap.h:324:5: note: expanded from macro 'hashmap_foreach'
__HASHMAP_FOREACH(__HASHMAP_MAKE_UNIQUE(__map), (key), (data), (h))
^
hashmap.h:32:10: note: expanded from macro '__HASHMAP_FOREACH'
for (HASHMAP_ITER(*(h)) __HASHMAP_UNIQUE(x, it) = hashmap_iter(h, &__HASHMAP_UNIQUE(x, it)); \
^
hashmap.h:96:5: note: expanded from macro 'HASHMAP_ITER'
struct { \
^
1 error generated.
Sorry about that. I used GNU toolchains when I was developing this project, and GCC gives more leeway and allows declaring an anonymous struct in a for
loop. There is a heated discussion on this topic here: https://stackoverflow.com/questions/11903232/declaring-anonymous-struct-in-for-loop-clang-fails-to-compile
The naïve fix for this issue would be to require the caller to declare the iterator externally, but this would significantly reduce the usability of the hashmap_foreach()
macro. You'd be looking at something like:
HASHMAP_ITER(map) it;
hashmap_foreach(it, key, val, &map) { ... }
I'll think about a solution. I may be able to define the iterator type in the hashmap structure, which will allow me to avoid declaring it in the for
loop, and placate more strict compilers like Clang and Visual Studio.
@NEU-Liu I just merged a fix. I added Clang to my continuous integration test build, and it's passing, so should be good to go.
for (struct {int foo; int bar;} i = {0}; i.foo < 10; i.foo++);
That works on clang 12 on Linux with -std=gnu17
and -std=gnu2x
, but not on FreeBSD with clang 13... Tried both -std=gnu17
and -std=gnu2x
...
Hi @bogen85 I will investigate differences in the C standard in the FreeBSD toolchain variants when time allows, but in the meantime, you might consider using the iterator interface instead of the foreach
macros. Here is an example:
HASHMAP_ITER(my_map) it;
for (it = hashmap_iter(&my_map); hashmap_iter_valid(&it); hashmap_iter_next(&it)) {
/* Access entry using hashmap_iter_*() functions */
}
The iterator interface is used internally by the foreach
macros, but has less "edgy" code in it that picky toolchains might balk at.