File: n3369.c

package info (click to toggle)
llvm-toolchain-21 1%3A21.1.6-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,245,028 kB
  • sloc: cpp: 7,619,726; ansic: 1,434,018; asm: 1,058,748; python: 252,740; f90: 94,671; objc: 70,685; lisp: 42,813; pascal: 18,401; sh: 8,601; ml: 5,111; perl: 4,720; makefile: 3,675; awk: 3,523; javascript: 2,409; xml: 892; fortran: 770
file content (196 lines) | stat: -rw-r--r-- 8,871 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// RUN: %clang_cc1 -fsyntax-only -std=c2y -pedantic -Wall -Wno-comment -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c2y -pedantic -Wall -Wno-comment -fexperimental-new-constant-interpreter -verify %s

/* WG14 N3369: Clang 21
 * _Lengthof operator
 *
 * Adds an operator to get the length of an array. Note that WG14 N3469 renamed
 * this operator to _Countof.
 */

#if !__has_feature(c_countof)
#error "Expected to have _Countof support"
#endif

#if !__has_extension(c_countof)
// __has_extension returns true if __has_feature returns true.
#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}}
  (void)_Countof(;    // expected-error {{expected expression}}
  (void)_Countof();   // expected-error {{expected expression}}
  (void)_Countof int; // expected-error {{expected expression}}
}

void test_semantic_failures() {
  (void)_Countof(1);         // expected-error {{'_Countof' requires an argument of array type; 'int' invalid}}
  int non_array;
  (void)_Countof non_array;  // expected-error {{'_Countof' requires an argument of array type; 'int' invalid}}  
  (void)_Countof(int);       // expected-error {{'_Countof' requires an argument of array type; 'int' invalid}}  
  (void)_Countof(test_semantic_failures); // expected-error {{invalid application of '_Countof' to a function type}}
  (void)_Countof(struct S);  // expected-error {{invalid application of '_Countof' to an incomplete type 'struct S'}} \
                                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) {
  static_assert(_Countof(global_array) == 12);
  static_assert(_Countof global_array == 12);  
  static_assert(_Countof(int[12]) == 12);

  // Use of a VLA makes it not a constant expression, same as with sizeof.
  int array[n];
  static_assert(_Countof(array)); // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(sizeof(array));   // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(_Countof(int[n]));// expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(sizeof(int[n]));  // expected-error {{static assertion expression is not an integral constant expression}}
  
  // Constant folding works the same way as sizeof, too.
  const int m = 12;
  int other_array[m];
  static_assert(sizeof(other_array));   // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(_Countof(other_array)); // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(sizeof(int[m]));        // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(_Countof(int[m]));      // expected-error {{static assertion expression is not an integral constant expression}}
  
  // Note that this applies to each array dimension.
  int another_array[n][7];
  static_assert(_Countof(another_array)); // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(_Countof(*another_array) == 7);

  // Only the first dimension is needed for constant evaluation; other
  // dimensions can be ignored.
  int yet_another_array[7][n];
  static_assert(_Countof(yet_another_array) == 7);
  static_assert(_Countof(*yet_another_array)); // expected-error {{static assertion expression is not an integral constant expression}}
  
  int one_more_time[n][n][7];
  static_assert(_Countof(one_more_time));  // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(_Countof(*one_more_time)); // expected-error {{static assertion expression is not an integral constant expression}}
  static_assert(_Countof(**one_more_time) == 7);
}

void test_with_function_param(int array[12], int (*array_ptr)[12], int static_array[static 12]) {
  (void)_Countof(array); // expected-error {{'_Countof' requires an argument of array type; 'int *' invalid}}
  static_assert(_Countof(*array_ptr) == 12);
  (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);
  static_assert(_Countof(*array) == 7);

  int mdarray[12][7][100][3];
  static_assert(_Countof(mdarray) == 12);
  static_assert(_Countof(*mdarray) == 7);
  static_assert(_Countof(**mdarray) == 100);
  static_assert(_Countof(***mdarray) == 3);
}

void test_unspecified_array_length() {
  static_assert(_Countof(int[])); // expected-error {{invalid application of '_Countof' to an incomplete type 'int[]'}}

  extern int x[][6][3];
  static_assert(_Countof(x)); // expected-error {{invalid application of '_Countof' to an incomplete type 'int[][6][3]'}}
  static_assert(_Countof(*x) == 6);
  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));
}

// Test that _Countof is able to look through typedefs.
void test_typedefs() {
  typedef int foo[12];
  foo f;
  static_assert(_Countof(foo) == 12);
  static_assert(_Countof(f) == 12);

  // Ensure multidimensional arrays also work.
  foo x[100];
  static_assert(_Generic(typeof(x), int[100][12] : 1, default : 0));
  static_assert(_Countof(x) == 100);
  static_assert(_Countof(*x) == 12);
}

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() {
  struct S {
    int array[10];
  } s;
  static_assert(_Countof(s.array) == 10);

  struct T {
    int count;
    int fam[];
  } t;
  static_assert(_Countof(t.fam)); // expected-error {{invalid application of '_Countof' to an incomplete type 'int[]'}}
}

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()]);
}