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.
> > 
> 

Reply via email to