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