[clang] Add more tests for _Countof (PR #133333)

via cfe-commits cfe-commits at lists.llvm.org
Mon May 5 14:34:21 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Alejandro Colomar (alejandro-colomar)

<details>
<summary>Changes</summary>

Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://github.com/llvm/llvm-project/pull/133125>

Cc: @<!-- -->AaronBallman 

I haven't yet tried to run these tests.  I've pasted and adapted them from the ones I wrote for my own implementation.  (I have a few more, which I'll adapt once I know I adapted these correctly.)

---
Revisions:

<details>
<summary>v2</summary>

-  Fix some expected diagnostics
-  Use `global_num` instead of `errno`.

```
$ git range-diff main gh/countof_tests countof_tests 
1:  fe746be5715d ! 1:  a651447d3fac Add more tests for _Countof
    @@ Commit message
     
         Link: <https://github.com/llvm/llvm-project/issues/102836>
         Link: <https://github.com/llvm/llvm-project/pull/133125>
    +    Cc: Aaron Ballman <aaron@<!-- -->aaronballman.com>
         Signed-off-by: Alejandro Colomar <alx@<!-- -->kernel.org>
     
      ## clang/test/C/C2y/n3369.c ##
    @@ clang/test/C/C2y/n3369.c: void test_with_function_param(int array[12], int (*arr
        (void)_Countof(static_array); // expected-error {{'_Countof' requires an argument of array type; 'int *' invalid}}
      }
      
    -+void test_func_fix_fix(int i, char (*a)[3][5], int (*x)[_Countof(*a)]);
    -+void test_func_fix_var(int i, char (*a)[3][i], int (*x)[_Countof(*a)]);
    -+void test_func_fix_uns(int i, char (*a)[3][*], int (*x)[_Countof(*a)]);
    ++void test_func_fix_fix(int i, char (*a)[3][5], int (*x)[_Countof(*a)]);  // expected-note {{passing argument to parameter}}
    ++void test_func_fix_var(int i, char (*a)[3][i], int (*x)[_Countof(*a)]);  // expected-note {{passing argument to parameter}}
    ++void test_func_fix_uns(int i, char (*a)[3][*], int (*x)[_Countof(*a)]);  // expected-note {{passing argument to parameter}}
     +
     +void test_funcs() {
     +  int i3[3];
     +  int i5[5];
     +  char c35[3][5];
     +  test_func_fix_fix(5, &c35, &i3);
    -+  test_func_fix_fix(5, &c35, &i5); // expected-error {{incompatible-pointer-types}}
    ++  test_func_fix_fix(5, &c35, &i5); // expected-error {{incompatible pointer types passing}}
     +  test_func_fix_var(5, &c35, &i3);
    -+  test_func_fix_var(5, &c35, &i5); // expected-error {{incompatible-pointer-types}}
    ++  test_func_fix_var(5, &c35, &i5); // expected-error {{incompatible pointer types passing}}
     +  test_func_fix_uns(5, &c35, &i3);
    -+  test_func_fix_uns(5, &c35, &i5); // expected-error {{incompatible-pointer-types}}
    ++  test_func_fix_uns(5, &c35, &i5); // expected-error {{incompatible pointer types passing}}
     +}
     +
      void test_multidimensional_arrays() {
    @@ clang/test/C/C2y/n3369.c: void test_unspecified_array_length() {
      }
      
     +void test_completed_array() {
    -+  int a[] = {1, 2, errno};
    ++  int a[] = {1, 2, global_num};
     +  static_assert(_Countof(a) == 3);
     +}
     +
```
</details>

<details>
<summary>v2b</summary>

-  Fix expected diagnostic messages

```
$ git range-diff main gh/countof_tests countof_tests 
1:  a651447d3fac ! 1:  6c5c502ca376 Add more tests for _Countof
    @@ clang/test/C/C2y/n3369.c: void test_with_function_param(int array[12], int (*arr
     +  int i5[5];
     +  char c35[3][5];
     +  test_func_fix_fix(5, &c35, &i3);
    -+  test_func_fix_fix(5, &c35, &i5); // expected-error {{incompatible pointer types passing}}
    ++  test_func_fix_fix(5, &c35, &i5); // expected-error {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
     +  test_func_fix_var(5, &c35, &i3);
    -+  test_func_fix_var(5, &c35, &i5); // expected-error {{incompatible pointer types passing}}
    ++  test_func_fix_var(5, &c35, &i5); // expected-error {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
     +  test_func_fix_uns(5, &c35, &i3);
    -+  test_func_fix_uns(5, &c35, &i5); // expected-error {{incompatible pointer types passing}}
    ++  test_func_fix_uns(5, &c35, &i5); // expected-error {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
     +}
     +
      void test_multidimensional_arrays() {
```
</details>

<details>
<summary>v2c</summary>

-  Fix expected diagnostic type

```
$ git range-diff main gh/countof_tests countof_tests 
1:  6c5c502ca376 ! 1:  b8f95e71efec Add more tests for _Countof
    @@ clang/test/C/C2y/n3369.c: void test_with_function_param(int array[12], int (*arr
     +  int i5[5];
     +  char c35[3][5];
     +  test_func_fix_fix(5, &c35, &i3);
    -+  test_func_fix_fix(5, &c35, &i5); // expected-error {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    ++  test_func_fix_fix(5, &c35, &i5); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
     +  test_func_fix_var(5, &c35, &i3);
    -+  test_func_fix_var(5, &c35, &i5); // expected-error {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    ++  test_func_fix_var(5, &c35, &i5); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
     +  test_func_fix_uns(5, &c35, &i3);
    -+  test_func_fix_uns(5, &c35, &i5); // expected-error {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    ++  test_func_fix_uns(5, &c35, &i5); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
     +}
     +
      void test_multidimensional_arrays() {
```
</details>

<details>
<summary>v2d</summary>

-  Fix expected diagnostics.

```
$ git range-diff main gh/countof_tests countof_tests 
1:  b8f95e71efec ! 1:  eb63ad49de45 Add more tests for _Countof
    @@ clang/test/C/C2y/n3369.c: void test_typedefs() {
        int array[0]; // expected-warning {{zero size arrays are an extension}}
        static_assert(_Countof(array) == 0);
        static_assert(_Countof(int[0]) == 0); // expected-warning {{zero size arrays are an extension}}
    -+  int multi_array[0][n]; // expected-warning {{zero size arrays are an extension}}
    ++  int multi_array[0][n]; // FIXME: Should trigger -Wzero-length-array
     +  static_assert(_Countof(multi_array) == 0);
     +  int another_one[0][3]; // expected-warning {{zero size arrays are an extension}}
     +  static_assert(_Countof(another_one) == 0);
    @@ clang/test/C/C2y/n3369.c: void test_compound_literals() {
      }
     +
     +static int test_f1();
    -+static int test_f2();  // expected-warning {{never defined}}
    ++static int test_f2(); // expected-warning {{function 'f' has internal linkage but is not defined}}
     +
     +void test_symbols() {
     +  int a[global_num][global_num];
```
</details>

<details>
<summary>v2e</summary>

-  Add comment about symbols.
-  tfix

```
$ git range-diff main gh/countof_tests countof_tests 
1:  eb63ad49de45 ! 1:  3660f83ad4be Add more tests for _Countof
    @@ clang/test/C/C2y/n3369.c: void test_compound_literals() {
        static_assert(_Countof((int[]){1, 2, 3, 4}) == 4);      
      }
     +
    ++/* We don't get a diagnostic for test_f1(), because it ends up unused
    ++ * as _Countof() results in an integer constant expression, which is not
    ++ * evaluated.  However, test_f2() ends up being evaluated, since 'a' is
    ++ * a VLA.
    ++ */
     +static int test_f1();
    -+static int test_f2(); // expected-warning {{function 'f' has internal linkage but is not defined}}
    ++static int test_f2(); // expected-warning {{function 'test_f2' has internal linkage but is not defined}}
     +
     +void test_symbols() {
     +  int a[global_num][global_num];
```
</details>

<details>
<summary>v3</summary>

-  Change `expected-warning` into a FIXME note (pre-existing false negative).
-  Add _Generic() code suggested by @<!-- -->frederick-vs-ja .

```
$ git range-diff main..@{u} main@{u}..HEAD
1:  3660f83ad4be ! 1:  d393955db896 Add more tests for _Countof
    @@ clang/test/C/C2y/n3369.c: void test_with_function_param(int array[12], int (*arr
        (void)_Countof(static_array); // expected-error {{'_Countof' requires an argument of array type; 'int *' invalid}}
      }
      
    -+void test_func_fix_fix(int i, char (*a)[3][5], int (*x)[_Countof(*a)]);  // expected-note {{passing argument to parameter}}
    -+void test_func_fix_var(int i, char (*a)[3][i], int (*x)[_Countof(*a)]);  // expected-note {{passing argument to parameter}}
    -+void test_func_fix_uns(int i, char (*a)[3][*], int (*x)[_Countof(*a)]);  // expected-note {{passing argument to parameter}}
    ++void test_func_fix_fix(int i, char (*a)[3][5], int (*x)[_Countof(*a)], char (*)[_Generic(x, int (*)[3]: 1)]);  // expected-note {{passing argument to parameter}}
    ++void test_func_fix_var(int i, char (*a)[3][i], int (*x)[_Countof(*a)], char (*)[_Generic(x, int (*)[3]: 1)]);  // expected-note {{passing argument to parameter}}
    ++void test_func_fix_uns(int i, char (*a)[3][*], int (*x)[_Countof(*a)], char (*)[_Generic(x, int (*)[3]: 1)]);  // expected-note {{passing argument to parameter}}
     +
     +void test_funcs() {
     +  int i3[3];
    @@ clang/test/C/C2y/n3369.c: void test_compound_literals() {
     + * a VLA.
     + */
     +static int test_f1();
    -+static int test_f2(); // expected-warning {{function 'test_f2' has internal linkage but is not defined}}
    ++static int test_f2(); // FIXME: Should trigger function 'test_f2' has internal linkage but is not defined
     +
     +void test_symbols() {
     +  int a[global_num][global_num];
```
</details>

<details>
<summary>v3b</summary>

-  Rebase

```
$ git range-diff main..@{u} main@{u}..HEAD
1:  d393955db896 = 1:  923856a504d8 Add more tests for _Countof
```
</details>

<details>
<summary>v3c</summary>

-  Add missing parameter.

```
$ git range-diff main..@{u} main@{u}..HEAD
1:  923856a504d8 ! 1:  f4f1f5661b0b Add more tests for _Countof
    @@ Commit message
     
      ## clang/test/C/C2y/n3369.c ##
     @@
    + #error "Expected to have _Countof support"
      #endif
      
    ++#define NULL  ((void *) 0)
    ++
      int global_array[12];
     +int global_multi_array[12][34];
     +int global_num;
    @@ clang/test/C/C2y/n3369.c: void test_with_function_param(int array[12], int (*arr
     +  int i3[3];
     +  int i5[5];
     +  char c35[3][5];
    -+  test_func_fix_fix(5, &c35, &i3);
    -+  test_func_fix_fix(5, &c35, &i5); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    -+  test_func_fix_var(5, &c35, &i3);
    -+  test_func_fix_var(5, &c35, &i5); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    -+  test_func_fix_uns(5, &c35, &i3);
    -+  test_func_fix_uns(5, &c35, &i5); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    ++  test_func_fix_fix(5, &c35, &i3, NULL);
    ++  test_func_fix_fix(5, &c35, &i5, NULL); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    ++  test_func_fix_var(5, &c35, &i3, NULL);
    ++  test_func_fix_var(5, &c35, &i5, NULL); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
    ++  test_func_fix_uns(5, &c35, &i3, NULL);
    ++  test_func_fix_uns(5, &c35, &i5, NULL); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
     +}
     +
      void test_multidimensional_arrays() {
```
</details>

---
Full diff: https://github.com/llvm/llvm-project/pull/133333.diff


1 Files Affected:

- (modified) clang/test/C/C2y/n3369.c (+51-1) 


``````````diff
diff --git a/clang/test/C/C2y/n3369.c b/clang/test/C/C2y/n3369.c
index 389828b52b6a2..db26040d8cf44 100644
--- a/clang/test/C/C2y/n3369.c
+++ b/clang/test/C/C2y/n3369.c
@@ -17,7 +17,11 @@
 #error "Expected to have _Countof support"
 #endif
 
+#define NULL  ((void *) 0)
+
 int global_array[12];
+int global_multi_array[12][34];
+int global_num;
 
 void test_parsing_failures() {
   (void)_Countof;     // expected-error {{expected expression}}
@@ -36,6 +40,12 @@ void test_semantic_failures() {
                                 expected-note {{forward declaration of 'struct S'}}
   struct T { int x; };
   (void)_Countof(struct T);  // expected-error {{'_Countof' requires an argument of array type; 'struct T' invalid}}
+  struct U { int x[3]; };
+  (void)_Countof(struct U);  // expected-error {{'_Countof' requires an argument of array type; 'struct U' invalid}}
+  int a[3];
+  (void)_Countof(&a);  // expected-error {{'_Countof' requires an argument of array type; 'int (*)[3]' invalid}}
+  int *p;
+  (void)_Countof(p);  // expected-error {{'_Countof' requires an argument of array type; 'int *' invalid}}
 }
 
 void test_constant_expression_behavior(int n) {
@@ -81,6 +91,22 @@ void test_with_function_param(int array[12], int (*array_ptr)[12], int static_ar
   (void)_Countof(static_array); // expected-error {{'_Countof' requires an argument of array type; 'int *' invalid}}
 }
 
+void test_func_fix_fix(int i, char (*a)[3][5], int (*x)[_Countof(*a)], char (*)[_Generic(x, int (*)[3]: 1)]);  // expected-note {{passing argument to parameter}}
+void test_func_fix_var(int i, char (*a)[3][i], int (*x)[_Countof(*a)], char (*)[_Generic(x, int (*)[3]: 1)]);  // expected-note {{passing argument to parameter}}
+void test_func_fix_uns(int i, char (*a)[3][*], int (*x)[_Countof(*a)], char (*)[_Generic(x, int (*)[3]: 1)]);  // expected-note {{passing argument to parameter}}
+
+void test_funcs() {
+  int i3[3];
+  int i5[5];
+  char c35[3][5];
+  test_func_fix_fix(5, &c35, &i3, NULL);
+  test_func_fix_fix(5, &c35, &i5, NULL); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
+  test_func_fix_var(5, &c35, &i3, NULL);
+  test_func_fix_var(5, &c35, &i5, NULL); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
+  test_func_fix_uns(5, &c35, &i3, NULL);
+  test_func_fix_uns(5, &c35, &i5, NULL); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[3]'}}
+}
+
 void test_multidimensional_arrays() {
   int array[12][7];
   static_assert(_Countof(array) == 12);
@@ -102,6 +128,11 @@ void test_unspecified_array_length() {
   static_assert(_Countof(**x) == 3);
 }
 
+void test_completed_array() {
+  int a[] = {1, 2, global_num};
+  static_assert(_Countof(a) == 3);
+}
+
 // Test that the return type of _Countof is what you'd expect (size_t).
 void test_return_type() {
   static_assert(_Generic(typeof(_Countof global_array), typeof(sizeof(0)) : 1, default : 0));
@@ -121,10 +152,14 @@ void test_typedefs() {
   static_assert(_Countof(*x) == 12);
 }
 
-void test_zero_size_arrays() {
+void test_zero_size_arrays(int n) {
   int array[0]; // expected-warning {{zero size arrays are an extension}}
   static_assert(_Countof(array) == 0);
   static_assert(_Countof(int[0]) == 0); // expected-warning {{zero size arrays are an extension}}
+  int multi_array[0][n]; // FIXME: Should trigger -Wzero-length-array
+  static_assert(_Countof(multi_array) == 0);
+  int another_one[0][3]; // expected-warning {{zero size arrays are an extension}}
+  static_assert(_Countof(another_one) == 0);
 }
 
 void test_struct_members() {
@@ -144,3 +179,18 @@ void test_compound_literals() {
   static_assert(_Countof((int[2]){}) == 2);
   static_assert(_Countof((int[]){1, 2, 3, 4}) == 4);	
 }
+
+/* We don't get a diagnostic for test_f1(), because it ends up unused
+ * as _Countof() results in an integer constant expression, which is not
+ * evaluated.  However, test_f2() ends up being evaluated, since 'a' is
+ * a VLA.
+ */
+static int test_f1();
+static int test_f2(); // FIXME: Should trigger function 'test_f2' has internal linkage but is not defined
+
+void test_symbols() {
+  int a[global_num][global_num];
+
+  static_assert(_Countof(global_multi_array[test_f1()]) == 34);
+  (void)_Countof(a[test_f2()]);
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/133333


More information about the cfe-commits mailing list