/*      $NetBSD: init_c99.c,v 1.5 2025/04/12 15:49:50 rillig Exp $      */
# 3 "init_c99.c"

// Tests for initialization in C99 or later, mainly for designators.
//
// See C99 6.7.8 "Initialization".

/* lint1-flags: -Sw -X 351 */

void use(const void *);

typedef struct any {
       const void *value;
} any;


// C99 6.7.8p11 says "optionally enclosed in braces".  Whether this wording
// means "a single pair of braces" or "as many pairs of braces as you want"
// is left for interpretation to the reader.
int scalar_without_braces = 3;
int scalar_with_optional_braces = { 3 };
int scalar_with_too_many_braces = {{ 3 }};
/* expect+1: error: too many initializers for 'int' [174] */
int scalar_with_too_many_initializers = { 3, 5 };


// See initialization_expr, 'handing over to INIT'.
void
struct_initialization_via_assignment(any arg)
{
       any local = arg;
       use(&local);
}


// See initialization_expr, initialization_init_array_from_string.
char static_duration[] = "static duration";
signed char static_duration_signed[] = "static duration";
unsigned char static_duration_unsigned[] = "static duration";
int static_duration_wchar[] = L"static duration";

// See init_expr.
void
initialization_by_braced_string(void)
{
       any local = { "hello" };
       use(&local);
}

void
initialization_by_redundantly_braced_string(void)
{
       any local = {{{{ "hello" }}}};
       use(&local);
}

/*
* Only scalar expressions and string literals may be enclosed by additional
* braces.  Since 'arg' is a struct, this is a compile-time error.
*/
void
initialization_with_too_many_braces(any arg)
{
       /* expect+1: error: cannot initialize 'pointer to const void' from 'struct any' [185] */
       any local = { arg };
       use(&arg);
}

// Some of the following examples are mentioned in the introduction comment
// in init.c.

int number = 12345;

int number_with_braces_and_comma = {
       12345,
};

int array_with_fixed_size[3] = {
       111,
       222,
       333,
       /* expect+1: error: too many array initializers, expected 3 [173] */
       444,
};

// See update_type_of_array_of_unknown_size.
int array_of_unknown_size[] = {
       111,
       222,
       333,
};

int array_flat[2][2] = {
       11,
       12,
       21,
       22
};

int array_nested[2][2] = {
       {
               11,
               12
       },
       {
               21,
               22
       }
};

int array_with_designators[] = {
       ['1'] = 111,
       ['5'] = 555,
       ['9'] = 999
};

int array_with_some_designators[] = {
       ['1'] = 111,
       222,
       ['9'] = 999
};

struct point {
       int x;
       int y;
};

struct point point = {
       3,
       4
};

struct point point_with_designators = {
       .y = 4,
       .x = 3,
};

struct point point_with_mixed_designators = {
       .x = 3,
       4,
       /* expect+1: error: too many struct/union initializers [172] */
       5,
       .x = 3,
};

/*
* Before cgram.y 1.230 from 2021-06-20, the grammar allowed either of the
* operators '.' or '->' to be used for the designators and had extra code
* to ensure that only '.' was actually used.
*/
struct point origin = {
       .x = 0,
       /* expect+1: error: syntax error '->' [249] */
       ->y = 0,
};

/* Ensure that the parser can recover from the parse error. */
struct point pythagoras = { 3, 4 };

int array_with_designator[] = {
       111,
       /* expect+1: error: syntax error 'designator '.member' is only for struct/union' [249] */
       .member = 222,
       333,
};

/*
* C99 6.7.8p11 says that the initializer of a scalar can be "optionally
* enclosed in braces".  It does not explicitly set an upper limit on the
* number of braces.  It also doesn't restrict the term "initializer" to only
* mean the "outermost initializer".  6.7.8p13 defines that a brace for a
* structure or union always means to descend into the type.  Both GCC 10 and
* Clang 8 already warn about these extra braces, nevertheless there is
* real-life code (the Postfix MTA) that exploits this corner case of the
* standard.
*/
struct point scalar_with_several_braces = {
       {{{3}}},
       {{{{4}}}},
};

struct rectangle {
       struct point top_left;
       struct point bottom_right;
};

/* C99 6.7.8p18 */
struct rectangle screen = {
       .bottom_right = {
               1920,
               1080,
       }
};

/*
* C99 6.7.8p22 says: At the _end_ of its initializer list, the array no
* longer has incomplete type.
*/
struct point points[] = {
       {
               /*
                * At this point, the size of the object 'points' is not known
                * yet since its type is still incomplete.  Lint could warn
                * about this, but GCC and Clang already do.
                *
                * Before init.c 1.179 from 2021.03.30, the type information
                * of 'points' was set too early, resulting in a negative
                * array size below.
                */
               sizeof(int[-(int)sizeof(points)]),
               4
       }
};


struct triangle {
       struct point points[3];
};

struct pentagon {
       struct point points[5];
};

struct geometry {
       struct pentagon pentagons[6];
       struct triangle triangles[10];
       struct point points[3][5][2];
};

/*
* Initialization of a complex struct containing nested arrays and nested
* structs.
*/
struct geometry geometry = {
       .pentagons[0].points[4].x = 1,
       .points[0][0][0] = { 0, 0 },
       .points[2][4][1] = {301, 302 },
       /* expect+1: error: array subscript 3 cannot be > 2 [168] */
       .points[3][0][0] = {3001, 3002 },
       /* expect+1: error: array subscript 5 cannot be > 4 [168] */
       .points[0][5][0] = {501, 502 },
       /* expect+1: error: array subscript 2 cannot be > 1 [168] */
       .points[0][0][2] = {21, 22 },
};

struct ends_with_unnamed_bit_field {
       int member;
       int:0;
} ends_with_unnamed_bit_field = {
       12345,
       /* expect+1: error: too many struct/union initializers [172] */
       23456,
};

char prefixed_message[] = {
       'E', ':', ' ',
       /* expect+1: warning: invalid combination of integer 'char' and pointer 'pointer to char' for 'init' [183] */
       "message\n",
};

char message_with_suffix[] = {
       "message",
       /* The excess character is not detected by lint but by compilers. */
       '\n',
};

struct ten {
       int i0;
       int i1;
       int i2;
       int i3;
       int i4;
       int i5;
       int i6;
       int i7;
       int i8;
       int i9;
};

struct ten ten = {
       .i3 = 3,
       4,
       5,
       6,
};


/*
* ISO C99 6.7.8 provides a large list of examples for initialization,
* covering all tricky edge cases.
*/

/* expect+1: warning: lossy conversion of 3.5 to 'int' [381] */
int c99_6_7_8_p24_example1_i = 3.5;
double _Complex c99_6_7_8_p24_example1_c = 5 + 3 * 1.0fi;

int c99_6_7_8_p25_example2[] = { 1, 3, 5 };

int c99_6_7_8_p26_example3a[4][3] = {
       { 1, 3, 5 },
       { 2, 4, 6 },
       { 3, 5, 7 },
};

int c99_6_7_8_p26_example3b[4][3] = {
       1, 3, 5, 2, 4, 6, 3, 5, 7
};

int c99_6_7_8_p27_example4[4][3] = {
       { 1 }, { 2 }, { 3 }, { 4 }
};

struct {
       int a[3], b;
} c99_6_7_8_p28_example5[] = {
       { 1 },
       2,
};

short c99_6_7_8_p29_example6a[4][3][2] = {
       { 1 },
       { 2, 3 },
       { 4, 5, 6 },
};

short c99_6_7_8_p29_example6b[4][3][2] = {
       1, 0, 0, 0, 0, 0,
       2, 3, 0, 0, 0, 0,
       4, 5, 6, 0, 0, 0,
};

short c99_6_7_8_p29_example6c[4][3][2] = {
       {
               { 1 },
       },
       {
               { 2, 3 },
       },
       {
               { 4, 5 },
               { 6 },
       }
};

void
c99_6_7_8_p31_example7(void)
{
       typedef int A[];

       A a = { 1, 2 }, b = { 3, 4, 5 };

       /* expect+1: error: negative array dimension (-8) [20] */
       typedef int reveal_sizeof_a[-(int)(sizeof(a))];
       /* expect+1: error: negative array dimension (-12) [20] */
       typedef int reveal_sizeof_b[-(int)(sizeof(b))];
}

char c99_6_7_8_p32_example8_s1[] = "abc",
        c99_6_7_8_p32_example8_t1[3] = "abc";
char c99_6_7_8_p32_example8_s2[] = { 'a', 'b', 'c', '\0' },
        c99_6_7_8_p32_example8_t2[3] = { 'a', 'b', 'c' };
char *c99_6_7_8_p32_example8_p = "abc";

enum { member_one, member_two };
const char *c99_6_7_8_p33_example9[] = {
       [member_two] = "member two",
       [member_one] = "member one",
};

struct {
       int quot, rem;
} c99_6_7_8_p34_example10 = { .quot = 2, .rem = -1 };

struct { int a[3], b; } c99_6_7_8_p35_example11[] =
       { [0].a = {1}, [1].a[0] = 2 };

int c99_6_7_8_p36_example12a[16] = {
       1, 3, 5, 7, 9, [16-5] = 8, 6, 4, 2, 0
};

int c99_6_7_8_p36_example12b[8] = {
       1, 3, 5, 7, 9, [8-5] = 8, 6, 4, 2, 0
};

union {
       int first_member;
       void *second_member;
       unsigned char any_member;
} c99_6_7_8_p38_example13 = { .any_member = 42 };


/*
* During initialization of an object of type array of unknown size, the type
* information on the symbol is updated in-place.  Ensure that this happens on
* a copy of the type.
*
* C99 6.7.8p31 example 7
*/
void
ensure_array_type_is_not_modified_during_initialization(void)
{
       typedef int array_of_unknown_size[];

       array_of_unknown_size a1 = { 1, 2, 3};

       switch (4) {
       case sizeof(array_of_unknown_size):
       /* expect+1: error: duplicate case '0' in switch [199] */
       case 0:
       case 3:
       case 4:
       case 12:
               break;
       }

       /* expect+1: error: negative array dimension (-12) [20] */
       typedef int reveal_sizeof_a1[-(int)(sizeof(a1))];
}

struct point unknown_member_name_beginning = {
       /* expect+1: error: type 'struct point' does not have member 'r' [101] */
       .r = 5,
       .x = 4,
       .y = 3,
};

struct point unknown_member_name_middle = {
       .x = 4,
       /* expect+1: error: type 'struct point' does not have member 'r' [101] */
       .r = 5,
       .y = 3,
};

struct point unknown_member_name_end = {
       .x = 4,
       .y = 3,
       /* expect+1: error: type 'struct point' does not have member 'r' [101] */
       .r = 5,
};

union value {
       int int_value;
       void *pointer_value;
};

union value unknown_union_member_name_first = {
       /* expect+1: error: type 'union value' does not have member 'unknown_value' [101] */
       .unknown_value = 4,
       .int_value = 3,
};

union value unknown_union_member_name_second = {
       .int_value = 3,
       /* expect+1: error: type 'union value' does not have member 'unknown_value' [101] */
       .unknown_value = 4,
};

struct point subscript_designator_on_struct = {
       /* expect+1: error: syntax error 'designator '[...]' is only for arrays' [249] */
       [0] = 3,
};

struct point unknown_member_on_struct = {
       /* expect+1: error: type 'struct point' does not have member 'member' [101] */
       .member[0][0].member = 4,
};

struct point unknown_member_on_scalar = {
       /* expect+1: error: syntax error 'scalar type cannot use designator' [249] */
       .x.y.z = 5,
};

struct {
       int:16;
       /* expect+2: warning: 'struct <unnamed>' has no named members [65] */
       /* expect+1: error: cannot initialize struct/union with no named member [179] */
} struct_with_only_unnamed_members = {
       123,
};

union {
       int:16;
       /* expect+2: warning: 'union <unnamed>' has no named members [65] */
       /* expect+1: error: cannot initialize struct/union with no named member [179] */
} union_with_only_unnamed_members = {
       123,
};

int designator_for_scalar = {
       /* expect+1: error: syntax error 'scalar type cannot use designator' [249] */
       .value = 3,
};

struct point member_designator_for_scalar_in_struct = {
       /* expect+1: error: syntax error 'scalar type cannot use designator' [249] */
       { .x = 3 },
};
struct point subscript_designator_for_scalar_in_struct = {
       /* expect+1: error: syntax error 'designator '[...]' is only for arrays' [249] */
       { [1] = 4 },
};


/* Seen in pcidevs_data.h, variable 'pci_words'. */
const char string_initialized_with_braced_literal[] = {
       "initializer",
};

// An array of unknown size containing strings.
char weekday_names[][4] = {
       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

/* nested struct/union initialization */
struct outer {
       int i;
       char c;
       union inner {
               short us;
               char uc;
       } u;
       char *s;
} struct_containing_union[] = {
       {
               .s = "foo",
               .c = 'b',
               .u = {
                       .uc = 'c'
               }
       },
       {
               .i = 1,
               .c = 'a',
               .u = {
                       .us = 2
               }
       },
};

/*
* The expansion of the offsetof macro may dereference a null pointer.
* Such expressions are allowed in initializers for objects with
* static duration.
*/
struct offset_and_data {
       unsigned long offset;
       unsigned long data;
};

struct offset_and_data offset_and_data = {
       (unsigned long)&(((struct offset_and_data *)0)->data),
       0,
};

// The size of the array is determined by the maximum index, not by the last
// one mentioned.
int arr_11[] = { [10] = 10, [0] = 0 };
/* expect+1: error: negative array dimension (-11) [20] */
typedef int ctassert_11[-(int)(sizeof(arr_11) / sizeof(arr_11[0]))];

// Without an explicit subscript designator, the subscript counts up.
int arr_3[] = { [1] = 1, [0] = 0, 1, 2 };
/* expect+1: error: negative array dimension (-3) [20] */
typedef int ctassert_3[-(int)(sizeof(arr_3) / sizeof(arr_3[0]))];


// C99 struct initialization using designators.
struct {
       int i;
       char *s;
} struct_array[] = {
       {
               .i = 2,
       },
       {
               .s = "foo"
       },
       {
               .i = 1,
               .s = "bar"
       },
       {
               .s = "foo",
               .i = -1
       },
};

// Ensure that deeply nested structs can be designated in an initializer.
int
init_deeply_nested_struct(void)
{
       struct rgb {
               unsigned red;
               unsigned green;
               unsigned blue;
       };

       struct hobbies {
               unsigned dancing: 1;
               unsigned running: 1;
               unsigned swimming: 1;
       };

       struct person {
               struct hobbies hobbies;
               struct rgb favorite_color;
       };

       struct city {
               struct person mayor;
       };

       struct state {
               struct city capital;
       };

       struct state st = {
               .capital.mayor.hobbies.dancing = 1,
               .capital.mayor.favorite_color.green = 0xFF,
               .capital.mayor.favorite_color.red = 0xFF,
       };
       return st.capital.mayor.favorite_color.red;
}

struct {
       int i[10];
       char *s;
} struct_array_with_inner_array[] = {
       {
               { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
               "foo"
       },
};

struct {
       int type;
       union {
               char b[20];
               short s[10];
               long l[5];
       } data;
} array_in_union_in_struct = {
       .type = 3,
       .data.l[0] = 4
};

// Somewhere between 2005.12.24.20.47.56 and 2006.12.19.19.06.44, lint could
// not initialize named members, see PR bin/20264.
union {
       char *p;
       int a[1];
} array_in_union = {
       .a = { 7 }
};

/*
* Initialization of a nested struct, in which some parts are initialized
* from non-constant expressions of the inner struct type.
*
* In C99, 6.7.8p13 describes exactly this case.
*/
void
init_nested_struct(void)
{

       typedef enum O1 {
               O1C = 101
       } O1;
       typedef enum O2 {
               O2C = 102
       } O2;
       typedef enum O3 {
               O3C = 103
       } O3;
       typedef enum I1 {
               I1C = 201
       } I1;
       typedef enum I2 {
               I2C = 202
       } I2;

       struct Inner1 {
               I1 i1;
       };

       struct Outer3Inner1 {
               O1 o1;
               struct Inner1 inner;
               O3 o3;
       };

       struct Inner1 inner1 = {
               I1C
       };
       struct Outer3Inner1 o3i1 = {
               O1C,
               inner1,
               O3C
       };

       O1 o1 = o3i1.o1;

       struct Inner2 {
               I1 i1;
               I2 i2;
       };

       struct Outer3Inner2 {
               O1 o1;
               struct Inner2 inner;
               O3 o3;
       };

       struct Inner2 inner2 = {
               I1C,
               I2C
       };
       struct Outer3Inner2 o3i2 = {
               O1C,
               inner2,
               O3C
       };
       o1 = o3i2.o1;

       /*
        * For static storage duration, each initializer expression must be a
        * constant expression.
        */
       static struct Inner2 inner3_static = {
               I1C,
               I2C
       };
       static struct Outer3Inner2 o3i2_static = {
               O1C,
               /* expect+1: error: non-constant initializer [177] */
               inner3_static,
               O3C
       };
}