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

Reply via email to