Am Montag, dem 26.08.2024 um 19:30 +0000 schrieb Qing Zhao: > Hi, Martin, > > Looks like that there is some issue when I tried to use the _Generic for the > testing cases, and then I narrowed down to a > small testing case that shows the problem without any change to GCC. > > [opc@qinzhao-ol8u3-x86 gcc]$ cat t1.c > struct annotated { > char b; > int c[]; > } *array_annotated; > extern void * counted_by_ref (int *); > > int main(int argc, char *argv[]) > { > typeof(counted_by_ref (array_annotated->c)) ret > = counted_by_ref (array_annotated->c); > _Generic (ret, void* : (void)0, default: *ret = 10); > > return 0; > } > [opc@qinzhao-ol8u3-x86 gcc]$ /home/opc/Install/latest/bin/gcc t1.c > t1.c: In function ‘main’: > t1.c:12:44: warning: dereferencing ‘void *’ pointer > 12 | _Generic (ret, void* : (void)0, default: *ret = 10); > | ^~~~ > t1.c:12:49: error: invalid use of void expression > 12 | _Generic (ret, void* : (void)0, default: *ret = 10); > | ^ > > Actually, I debugged this issue into gcc’s C routine > “c_parser_generic_selection”. > And found that, the “default” branch of the _Generic is always parsed even > though there is already > a match in the previous conditions. Therefore, *ret = 10 is parsed even when > ret is a void *, therefore the compilation error. > > So, I am not sure whether this is the correct behavior of the operator > _Generic? > Or is there any obvious error in the above small testing case? > If So, then looks like that we cannot use the _Generic operator for this > purpose. > > Any comments on this? >
Ah, right. This is indeed the correct behavior for _Generic, and I have overlooked this. One could work around it like this: __auto_type ret = counted_by_ref (array_annotated->c); *_Generic (ret, void*: &(int){ }, default: ret) = 10; or, if one expects only specific types: __auto_type ret = counted_by_ref (array_annotated->c); _Generic (ret, void*: 0, int*: *(int*)ret = 10, size_t*: *(size_t*)ret = 10); But yes, a bit less elegant. Martin > Thanks a lot for your help. > > Qing > > > > On Aug 21, 2024, at 11:43, Martin Uecker <uec...@tugraz.at> wrote: > > > > Am Mittwoch, dem 21.08.2024 um 15:24 +0000 schrieb Qing Zhao: > > > > > > > > But if we changed it to return a void pointer, we could make this > > > > a compile-time check: > > > > > > > > auto ret = __builtin_get_counted_by(__p->FAM); > > > > > > > > _Generic(ret, void*: (void)0, default: *ret = COUNT); > > > > > > Is there any benefit to return a void pointer than a SIZE_T pointer for > > > the NULL pointer? > > > > Yes! You can test with _Generic (or __builtin_types_compatible_p) > > at compile-time based on the type whether you can set *ret to COUNT > > or not as in the example above. > > > > So it is not a weird run-time test which needs to be optimized > > away. > > >