Am Donnerstag, dem 14.08.2025 um 12:19 +0200 schrieb Alejandro Colomar: > Hi Martin, > > On Thu, Aug 14, 2025 at 11:01:05AM +0200, Alejandro Colomar wrote: > > +void > > +decay_obvious (int a[2]) > > +{ > > + _Countof (typeof (a)); /* { dg-error "invalid" } */ > > + _Countof (a + 1); /* { dg-error "invalid" } */ > > It didn't occur to me the following test: > > alx@devuan:~/tmp$ cat c.c | nl -ba > 1 int > 2 main(int argc, char *argv[argc + 1]) > 3 { > 4 argv++; > 5 > 6 return _Countof(argv); > 7 } > alx@devuan:~/tmp$ /opt/local/gnu/gcc/countof_ap/bin/gcc -Wall -Wextra > c.c > alx@devuan:~/tmp$ ./a.out > alx@devuan:~/tmp$ echo $? > 2 > > This is a weak point, which requires -farray-parameters-are-const as > proposed in: > <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121271> > > I'm willing to accept it as a known limitation of _Countof(), and > tell that programmers to use const (or use -farray-parameters-are-const > once we provide it) to ensure safety.
You could also add a warning when _Countof is applied to a non-constant pointer. > > So, I stand by this patch even with this known limitation. > > On the other, hand, it may be a GCC existing bug? I see that > _Countof(a+0) remembers the array number of elements but _Countof(a+1) > doesn't. Maybe once you do a++ you should also forget the number of > elements (or update it)? Difficult, as this is then flow-sensitive and not simply a property of 'a'. That a + 0 works because the expression is folded before. Maybe you could change it to take the expression before folding? Martin > > > Have a lovely day! > Alex > > > + _Countof (42 ? NULL : a); /* { dg-error "invalid" } */ > > + > > + int *p = a; > > + > > + _Countof (p); /* { dg-error "invalid" } */ > > + > > + typeof(a) a2; > > + > > + _Countof (a2); /* { dg-error "invalid" } */ > > +} > > + > > +/* These would decay if they were arrays, but being a parameter, it's > > works. */ > > +void > > +no_decay_surprising (int a[2]) > > +{ > > + _Static_assert (2 == _Countof (a + 0)); > > + _Static_assert (2 == _Countof (&*a)); > > + _Static_assert (2 == _Countof (42, a)); > > + _Static_assert (2 == _Countof (42 ? a : a)); > > + _Static_assert (2 == _Countof (42 ? a : NULL)); > > +} > > + > > +void > > +no_decay_obvious (int a[2]) > > +{ > > + _Static_assert (2 == _Countof (a)); > > + _Static_assert (2 == _Countof (*&a)); > > + _Static_assert (2 == _Countof (*(&a + 0))); > > +} > > + > > +/* It would not decay if it were an array, but being a parameter, it > > decays. */ > > +void > > +decay_surprising (int a[2]) > > +{ > > + _Countof (*(&a + 1)); /* { dg-error "invalid" } */ > > +} > > diff --git a/gcc/testsuite/gcc.dg/countof-param-pedantic.c > > b/gcc/testsuite/gcc.dg/countof-param-pedantic.c > > new file mode 100644 > > index 000000000000..7d52f27a72bb > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/countof-param-pedantic.c > > @@ -0,0 +1,11 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-std=c2y -pedantic" } */ > > + > > +#include <stdcountof.h> > > + > > +int > > +f (int a[1]) > > +{ > > + countof(a); /* { dg-warning "ISO C does not support array parameters" } > > */ > > + _Countof(a); /* { dg-warning "ISO C does not support array parameters" > > } */ > > +} > > diff --git a/gcc/testsuite/gcc.dg/countof-param.c > > b/gcc/testsuite/gcc.dg/countof-param.c > > new file mode 100644 > > index 000000000000..e03f8b9389db > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/countof-param.c > > @@ -0,0 +1,25 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-Wvla-parameter -Warray-parameter=2" } */ > > + > > +#define assert(e) ((e) ? (void) 0 : __builtin_abort ()) > > + > > +int f1 (int , int a[3]) { return _Countof(a); } > > +int f2 (int , int a[2]) { return _Countof(a); } > > + > > +int f1 (int , int a[2]); /* { dg-warning "with mismatched bound" } */ > > +int f2 (int n, int a[n]); /* { dg-warning "declared as a variable length > > array" } */ > > + > > +int g1 (int , int a[3]); > > +int g2 (int , int a[2]); > > + > > +int g1 (int , int a[2]) { return _Countof(a); } // { dg-warning "with > > mismatched bound" } */ > > +int g2 (int n, int a[n]) { return _Countof(a); } // { dg-warning > > "declared as a variable length array" } */ > > + > > +int > > +main (void) > > +{ > > + assert (3 == f1 (42, (int [42]){})); > > + assert (2 == f2 (42, (int [42]){})); > > + assert (2 == g1 (42, (int [42]){})); > > + assert (42 == g2 (42, (int [42]){})); > > +} > > -- > > 2.50.1 > >