DavidLeeds / hashmap

Templated type-safe hashmap implementation in C using open addressing and linear probing for collision resolution.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.