Hi!

Here's a patch co-authored by Martin and I.  It adds support for array
parameters in _Countof, which will enable writing safer code that only
specifies array bounds in function calls when strictly necessary,
reducing the chances for mistakes.

Here's an example program that never specifies bounds except in the
function prototypes and wrapper macros that insert _Countof() calls.
Once those are correct, which is easier than guaranteeing correctness of
all callers, the bounds are correct.

        alx@devuan:~/tmp$ cat present.c | nl -ba
             1  #include <stddef.h>
             2  #include <stdio.h>
             3  #include <stdlib.h>
             4  
             5  #define MALLOCARRAY(n, T)  ((typeof(T) (*)[n]) 
reallocarray(NULL, n, sizeof(T)))
             6  
             7  #define F(a)  f(_Countof(a), a)
             8  #define G(a)  g(_Countof(a), a)
             9  #define H(a)  h(_Countof(a), a)
            10  #define I(a)  i(_Countof(a), a)
            11  #define P(a)  p(_Countof(a), a)
            12  
            13  void f(size_t n, int a[n]);
            14  void g(size_t n, int a[n]);
            15  void h(size_t n, int a[n]);
            16  void i(size_t n, int a[n]);
            17  void p(size_t n, int a[n]);
            18  
            19  int
            20  main(void)
            21  {
            22          int (*ap)[7] = MALLOCARRAY(7, int);
            23  
            24          F(*ap);
            25          P(*ap);
            26  }
            27  
            28  void f(size_t n, int a[n]) { G(a); }
            29  void g(size_t n, int a[n]) { H(a); }
            30  void h(size_t n, int a[n]) { I(a); }
            31  void i(size_t n, int a[n])
            32  {
            33          for (size_t j = 0; j < _Countof(a); j++)
            34                  a[j] = j;
            35  }
            36  void p(size_t n, int a[n])
            37  {
            38          for (size_t j = 0; j < _Countof(a); j++)
            39                  printf("%d\n", a[j]);
            40  }
        alx@devuan:~/tmp$ /opt/local/gnu/gcc/countof_ap/bin/gcc -Wall -Wextra 
present.c 
        alx@devuan:~/tmp$ ./a.out 
        0
        1
        2
        3
        4
        5
        6

Of course, programmers sometimes need to pass a slice of an array, which
is still a point where mistakes can be made, but the mistake surface is
much smaller.

This has passed regression testing on my amd64 computer:

        alx@devuan:/srv/alx/src/gnu/gcc/countof_ap$ git log --oneline 
gnu/master..cap1
        b5e67c7fb806 (HEAD -> countof_ap, tag: cap1) c: Add support for array 
parameters in _Co>
        alx@devuan:/srv/alx/src/gnu/gcc/countof_ap$ git reset gnu/master --h
        HEAD is now at a440b382e432 tree-optimization/121514 - ICE with recent 
VN improvement
        alx@devuan:/srv/alx/src/gnu/gcc/countof_ap$ mkdir ../cap1
        alx@devuan:/srv/alx/src/gnu/gcc/countof_ap$ cd ../cap1
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ /bin/time ../countof_ap/configure 
--disable-multilib --prefix=/opt/local/gnu/gcc/cap1 |& ts -s | tail -n 3; echo 
$?
        00:00:02 config.status: creating Makefile
        00:00:02 1.60user 0.41system 0:01.68elapsed 119%CPU (0avgtext+0avgdata 
58188maxresident)k
        00:00:02 0inputs+8512outputs (0major+296952minor)pagefaults 0swaps
        0
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ /bin/time make -j12 bootstrap |& 
ts -s | tail -n 3; echo $?
        00:29:03 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/cap1'
        00:29:03 14854.54user 351.05system 29:03.04elapsed 872%CPU 
(0avgtext+0avgdata 1491724maxresident)k
        00:29:03 7432inputs+48894016outputs 
(1057major+125712628minor)pagefaults 0swaps
        0
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ /bin/time make check |& ts -s | 
tail -n 3; echo $?06:54:30 make[1]: Leaving directory 
'/srv/alx/src/gnu/gcc/cap1'
        06:54:30 22580.22user 2458.85system 6:54:30elapsed 100%CPU 
(0avgtext+0avgdata 1041248maxresident)k
        06:54:30 747704inputs+49565368outputs 
(3254major+1065983823minor)pagefaults 0swaps
        0
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ cd ../countof_ap/
        alx@devuan:/srv/alx/src/gnu/gcc/countof_ap$ git merge --ff-only cap1
        Updating a440b382e432..b5e67c7fb806
        Fast-forward
         gcc/c/c-typeck.cc                             | 50 
+++++++++++++++++++----
         gcc/doc/extend.texi                           | 11 +++++
         gcc/testsuite/gcc.dg/countof-compile.c        |  8 +---
         gcc/testsuite/gcc.dg/countof-param-compile.c  | 76 
+++++++++++++++++++++++++++++++++++
         gcc/testsuite/gcc.dg/countof-param-pedantic.c | 11 +++++
         gcc/testsuite/gcc.dg/countof-param.c          | 25 ++++++++++++
         6 files changed, 166 insertions(+), 15 deletions(-)
         create mode 100644 gcc/testsuite/gcc.dg/countof-param-compile.c
         create mode 100644 gcc/testsuite/gcc.dg/countof-param-pedantic.c
         create mode 100644 gcc/testsuite/gcc.dg/countof-param.c
        alx@devuan:/srv/alx/src/gnu/gcc/countof_ap$ cd ..
        alx@devuan:/srv/alx/src/gnu/gcc$ mv cap1/ cap1_b4
        alx@devuan:/srv/alx/src/gnu/gcc$ mkdir cap1
        alx@devuan:/srv/alx/src/gnu/gcc$ cd cap1
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ /bin/time ../countof_ap/configure 
--disable-multilib --prefix=/opt/local/gnu/gcc/cap1 |& ts -s | tail -n 3; echo 
$?
        00:00:01 config.status: creating Makefile
        00:00:01 1.51user 0.29system 0:01.51elapsed 119%CPU (0avgtext+0avgdata 
58188maxresident)k
        00:00:01 5360inputs+8512outputs (0major+294355minor)pagefaults 0swaps
        0
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ /bin/time make -j12 bootstrap |& 
ts -s | tail -n 3; echo $?
        00:28:39 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/cap1'
        00:28:39 14724.90user 348.58system 28:39.00elapsed 876%CPU 
(0avgtext+0avgdata 1491500maxresident)k
        00:28:39 9792inputs+48912704outputs (474major+127163137minor)pagefaults 
0swaps
        0
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ /bin/time make check |& ts -s | 
tail -n 3; echo $?
        07:10:04 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/cap1'
        07:10:04 23505.49user 2504.21system 7:10:03elapsed 100%CPU 
(0avgtext+0avgdata 1040928maxresident)k
        07:10:04 125624inputs+49566296outputs 
(3531major+1091343152minor)pagefaults 0swaps
        0
        alx@devuan:/srv/alx/src/gnu/gcc/cap1$ find -type f | grep '\.sum$' | 
while read f; do diff -u ../cap1_b4/$f <(cat $f | sed s,/home/,/srv/,); done
        --- ../cap1_b4/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum        
2025-08-12 22:05:07.371228042 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.738374420 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 22:05:05 2025
        +Test run by alx on Thu Aug 14 06:17:05 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === libitm tests ===
        --- ../cap1_b4/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum  
2025-08-12 22:05:09.188035238 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.742374460 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 22:05:07 2025
        +Test run by alx on Thu Aug 14 06:17:07 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === libatomic tests ===
        --- ../cap1_b4/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum      
2025-08-12 22:05:05.247204895 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.742374460 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 21:49:34 2025
        +Test run by alx on Thu Aug 14 06:01:52 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === libgomp tests ===
        --- 
../cap1_b4/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum       
2025-08-12 21:49:12.806400698 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.754374580 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 18:21:51 2025
        +Test run by alx on Thu Aug 14 02:17:17 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === libstdc++ tests ===
        --- ../cap1_b4/./gcc/testsuite/objc/objc.sum    2025-08-12 
18:21:24.478438464 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.762374660 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 18:20:26 2025
        +Test run by alx on Thu Aug 14 02:15:58 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === objc tests ===
        --- ../cap1_b4/./gcc/testsuite/g++/g++.sum      2025-08-12 
17:45:03.165753359 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.766374700 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 16:47:58 2025
        +Test run by alx on Thu Aug 14 00:43:52 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === g++ tests ===
        --- ../cap1_b4/./gcc/testsuite/gcc/gcc.sum      2025-08-12 
16:47:57.835002964 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.842375460 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 15:10:43 2025
        +Test run by alx on Wed Aug 13 23:07:08 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === gcc tests ===
        @@ -81811,26 +81811,47 @@
         PASS: gcc.dg/countof-compat.c  (test for warnings, line 8)
         PASS: gcc.dg/countof-compat.c (test for excess errors)
         PASS: gcc.dg/countof-compile.c  (test for errors, line 23)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 27)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 38)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 46)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 34)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 40)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 58)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 61)
         PASS: gcc.dg/countof-compile.c  (test for errors, line 64)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 67)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 70)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 76)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 77)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 78)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 79)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 80)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 81)
         PASS: gcc.dg/countof-compile.c  (test for errors, line 82)
         PASS: gcc.dg/countof-compile.c  (test for errors, line 83)
         PASS: gcc.dg/countof-compile.c  (test for errors, line 84)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 85)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 86)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 87)
         PASS: gcc.dg/countof-compile.c  (test for errors, line 88)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 89)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 90)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 94)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 114)
        -PASS: gcc.dg/countof-compile.c  (test for errors, line 123)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 108)
        +PASS: gcc.dg/countof-compile.c  (test for errors, line 117)
         PASS: gcc.dg/countof-compile.c (test for excess errors)
         PASS: gcc.dg/countof-no-compat.c (test for excess errors)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 20)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 21)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 22)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 30)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 33)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 34)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 39)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 40)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 41)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 45)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 49)
        +PASS: gcc.dg/countof-param-compile.c  (test for errors, line 75)
        +PASS: gcc.dg/countof-param-compile.c (test for excess errors)
        +PASS: gcc.dg/countof-param-pedantic.c  (test for warnings, line 9)
        +PASS: gcc.dg/countof-param-pedantic.c  (test for warnings, line 10)
        +PASS: gcc.dg/countof-param-pedantic.c (test for excess errors)
        +PASS: gcc.dg/countof-param.c  (test for warnings, line 9)
        +PASS: gcc.dg/countof-param.c  (test for warnings, line 10)
        +PASS: gcc.dg/countof-param.c  (test for warnings, line 15)
        +PASS: gcc.dg/countof-param.c  (test for warnings, line 16)
        +PASS: gcc.dg/countof-param.c (test for excess errors)
        +PASS: gcc.dg/countof-param.c execution test
         PASS: gcc.dg/countof-pedantic-errors.c  (test for errors, line 8)
         PASS: gcc.dg/countof-pedantic-errors.c (test for excess errors)
         PASS: gcc.dg/countof-pedantic.c  (test for warnings, line 8)
        @@ -218959,7 +218980,7 @@
         
                        === gcc Summary ===
         
        -# of expected passes           212922
        +# of expected passes           212943
         # of unexpected failures       528
         # of unexpected successes      2
         # of expected failures         1478
        --- ../cap1_b4/./gcc/testsuite/gfortran/gfortran.sum    2025-08-12 
18:20:25.729779170 +0200
        +++ /dev/fd/63  2025-08-14 10:09:07.942376461 +0200
        @@ -1,4 +1,4 @@
        -Test run by alx on Tue Aug 12 17:45:03 2025
        +Test run by alx on Thu Aug 14 01:40:28 2025
         Native configuration is x86_64-pc-linux-gnu
         
                        === gfortran tests ===


Have a lovely day!
Alex


Martin Uecker (1):
  c: Add support for array parameters in _Countof

 gcc/c/c-typeck.cc                             | 50 ++++++++++--
 gcc/doc/extend.texi                           | 11 +++
 gcc/testsuite/gcc.dg/countof-compile.c        |  8 +-
 gcc/testsuite/gcc.dg/countof-param-compile.c  | 76 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-param-pedantic.c | 11 +++
 gcc/testsuite/gcc.dg/countof-param.c          | 25 ++++++
 6 files changed, 166 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-param-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-param-pedantic.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-param.c

Range-diff against v0:
-:  ------------ > 1:  b5e67c7fb806 c: Add support for array parameters in 
_Countof

base-commit: a440b382e43203857de9195eb526c4a16f21ceb1
-- 
2.50.1

Reply via email to