// RUN: %clang_cc1 %s      -std=c++23 -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,bitfieldwarnings,cpp -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
// RUN: %clang_cc1 %s      -std=c++23 -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,cpp -Wno-unused-value -Wno-unused-but-set-variable

// RUN: %clang_cc1 %s -x c -std=c23   -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,c -Wno-unused-value -Wno-unused-but-set-variable
// RUN: %clang_cc1 %s -x c -std=c23   -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,bitfieldwarnings,c -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion


typedef enum A {
  A_a,
  A_b,
  A_c,
  A_d
} A;

#ifdef __cplusplus
#define DEFINE_ENUM(_Name, _Type, ...) enum class _Name : _Type { __VA_ARGS__ } ;
#define ENUM_CLASS_REF(_Name, _Enum) _Name::_Enum
#else
#define DEFINE_ENUM(_Name, _Type, ...) typedef enum _Name : _Type { __VA_ARGS__ } _Name;
#define ENUM_CLASS_REF(_Name, _Enum) _Enum
#endif

DEFINE_ENUM(B, int, B_a, B_b, B_c, B_d );
DEFINE_ENUM(C, unsigned, C_a, C_b, C_c, C_d );
DEFINE_ENUM(D, unsigned, D_a, D_b);

// Not using templates here so we can more easily distinguish the responsible
// party for each warning

typedef struct S_A {
  A field1 : 1; // #S_A_field1
  A field2 : 2; // #S_A_field2
  A field3 : 8; // #S_A_field3
  __attribute__((preferred_type(A))) // #preferred_S_A_field4
  unsigned field4 : 1; // #S_A_field4
  __attribute__((preferred_type(A)))
  unsigned field5 : 2; // #S_A_field5
  __attribute__((preferred_type(A)))
  unsigned field6 : 8; // #S_A_field6
  __attribute__((preferred_type(A))) // #preferred_S_A_field7
  int field7 : 1; // #S_A_field7
  __attribute__((preferred_type(A))) // #preferred_S_A_field8
  int field8 : 2; // #S_A_field8
  __attribute__((preferred_type(A)))
  int field9 : 8; // #S_A_field9
  __attribute__((preferred_type(A)))
  D field10 : 1; // #S_A_field10
  __attribute__((preferred_type(A))) // #preferred_S_A_field11
  D field11 : 2; // #S_A_field11
  __attribute__((preferred_type(A)))
  D field12 : 8; // #S_A_field12
} S_A;

typedef struct S_B {
  B field1 : 1; // #S_B_field1
  B field2 : 2; // #S_B_field2
  B field3 : 8; // #S_B_field3
  __attribute__((preferred_type(B))) // #preferred_S_B_field4
  unsigned field4 : 1; // #S_B_field4
  __attribute__((preferred_type(B)))
  unsigned field5 : 2; // #S_B_field5
  __attribute__((preferred_type(B)))
  unsigned field6 : 8; // #S_B_field6
  __attribute__((preferred_type(B))) // #preferred_S_B_field7
  int field7 : 1; // #S_B_field7
  __attribute__((preferred_type(B))) // #preferred_S_B_field8
  int field8 : 2; // #S_B_field8
  __attribute__((preferred_type(B)))
  int field9 : 8; // #S_B_field9
  __attribute__((preferred_type(B)))
  D field10 : 1; // #S_B_field10
  __attribute__((preferred_type(B))) // #preferred_S_B_field11
  D field11 : 2; // #S_B_field11
  __attribute__((preferred_type(B)))
  D field12 : 8; // #S_B_field12
} S_B;

typedef struct S_C {
  C field1 : 1; // #S_C_field1
  C field2 : 2; // #S_C_field2
  C field3 : 8; // #S_C_field3
  __attribute__((preferred_type(C))) // #preferred_S_C_field4
  unsigned field4 : 1; // #S_C_field4
  __attribute__((preferred_type(C)))
  unsigned field5 : 2; // #S_C_field5
  __attribute__((preferred_type(C)))
  unsigned field6 : 8; // #S_C_field6
  __attribute__((preferred_type(C))) // #preferred_S_C_field7
  int field7 : 1; // #S_C_field7
  __attribute__((preferred_type(C))) // #preferred_S_C_field8
  int field8 : 2; // #S_C_field8
  __attribute__((preferred_type(C)))
  int field9 : 8; // #S_C_field9
  __attribute__((preferred_type(C)))
  D field10 : 1; // #S_C_field10
  __attribute__((preferred_type(C))) // #preferred_S_C_field11
  D field11 : 2; // #S_C_field11
  __attribute__((preferred_type(C)))
  D field12 : 8; // #S_C_field12
} S_C;

void read_enumA(S_A *s) {
  A x;
  x = s->field1;
  x = s->field2;
  x = s->field3;
  x = (A)s->field4;
  x = (A)s->field5;
  x = (A)s->field6;
  x = (A)s->field7;
  x = (A)s->field8;
  x = (A)s->field9;
  x = (A)s->field10;
  x = (A)s->field11;
  x = (A)s->field12;
}

void read_enumB(S_B *s) {
  B x;
  x = s->field1;
  x = s->field2;
  x = s->field3;
  x = (B)s->field4;
  x = (B)s->field5;
  x = (B)s->field6;
  x = (B)s->field7;
  x = (B)s->field8;
  x = (B)s->field9;
  x = (B)s->field10;
  x = (B)s->field11;
  x = (B)s->field12;
}

void read_enumC(S_C *s) {
  C x;
  x = s->field1;
  x = s->field2;
  x = s->field3;
  x = (C)s->field4;
  x = (C)s->field5;
  x = (C)s->field6;
  x = (C)s->field7;
  x = (C)s->field8;
  x = (C)s->field9;
  x = (C)s->field10;
  x = (C)s->field11;
  x = (C)s->field12;
}

void write_enumA(S_A *s, A x) {
  s->field1 = x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}}
  // bitfieldwarnings-note@#S_A_field1 {{widen this field to 2 bits to store all values of 'A'}}
  s->field2 = x;
  s->field3 = x;
  s->field4 = x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of 'A'}}
  // bitfieldwarnings-note@#S_A_field4 {{widen this field to 2 bits to store all values of 'A'}}
  s->field5 = x;
  s->field6 = x;
  s->field7 = x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of 'A'}}
  // bitfieldwarnings-note@#S_A_field7 {{widen this field to 2 bits to store all values of 'A'}}
  s->field8 = x;
  // bitfieldwarnings-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of 'A'}}
  // bitfieldwarnings-note@#S_A_field8 {{consider making the bit-field type unsigned}}
  s->field9 = x;
  s->field10 = (D)x;
  s->field11 = (D)x;
  s->field12 = (D)x;
}

void write_enumB(S_B *s, B x) {
  s->field1 = x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}}
  // bitfieldwarnings-note@#S_B_field1 {{widen this field to 2 bits to store all values of 'B'}}
  s->field2 = x;
  // bitfieldwarnings-warning@-1 {{signed bit-field 'field2' needs an extra bit to represent the largest positive enumerators of 'B'}}
  // bitfieldwarnings-note@#S_B_field2 {{consider making the bit-field type unsigned}}
  s->field3 = x;
  s->field4 = (unsigned)x;
  // expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}}
  // expected-note@#S_B_field4 {{widen this field to 2 bits to store all values of 'B'}}
  // expected-note@#preferred_S_B_field4 {{preferred type for bit-field 'B' specified here}}
  s->field5 = (unsigned)x;
  s->field6 = (unsigned)x;
  s->field7 = (int)x;
  // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}}
  // expected-note@#S_B_field7 {{widen this field to 2 bits to store all values of 'B'}}
  // expected-note@#preferred_S_B_field7 {{preferred type for bit-field 'B' specified here}}
  s->field8 = (int)x;
  // expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'B'}}
  // expected-note@#S_B_field8 {{consider making the bit-field type unsigned}}
  // expected-note@#preferred_S_B_field8 {{preferred type for bit-field 'B' specified here}}
  s->field9 = (int)x;
  s->field10 = (D)x;
  s->field11 = (D)x;
  s->field12 = (D)x;
}

void write_enumC(S_C *s, C x) {
  s->field1 = x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}}
  // bitfieldwarnings-note@#S_C_field1 {{widen this field to 2 bits to store all values of 'C'}}
  s->field2 = x;
  s->field3 = x;
  s->field4 = (unsigned)x;
  // expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}}
  // expected-note@#S_C_field4 {{widen this field to 2 bits to store all values of 'C'}}
  // expected-note@#preferred_S_C_field4 {{preferred type for bit-field 'C' specified here}}
  s->field5 = (unsigned)x;
  s->field6 = (unsigned)x;
  s->field7 = (int)x;
  // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}}
  // expected-note@#S_C_field7 {{widen this field to 2 bits to store all values of 'C'}}
  // expected-note@#preferred_S_C_field7 {{preferred type for bit-field 'C' specified here}}
  s->field8 = (int)x;
  // expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'C'}}
  // expected-note@#S_C_field8 {{consider making the bit-field type unsigned}}
  // expected-note@#preferred_S_C_field8 {{preferred type for bit-field 'C' specified here}}
  s->field9 = (int)x;
  s->field10 = (D)x;
  s->field11 = (D)x;
  s->field12 = (D)x;
}

void write_enum_intA(struct S_A *s, int x) {
  s->field1 = (A)x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}}
  // bitfieldwarnings-note@#S_A_field1 {{widen this field to 2 bits to store all values of 'A'}}
  s->field2 = (A)x;
  s->field3 = (A)x;
  s->field4 = x;
  // expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'A'}}
  // expected-note@#S_A_field4 {{widen this field to 2 bits to store all values of 'A'}}
  // expected-note@#preferred_S_A_field4 {{preferred type for bit-field 'A' specified here}}
  s->field5 = x;
  s->field6 = x;
  s->field7 = x;
  // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'A'}}
  // expected-note@#S_A_field7 {{widen this field to 2 bits to store all values of 'A'}}
  // expected-note@#preferred_S_A_field7 {{preferred type for bit-field 'A' specified here}}
  s->field8 = x;
  // expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}}
  // expected-note@#S_A_field8 {{consider making the bit-field type unsigned}}
  // expected-note@#preferred_S_A_field8 {{preferred type for bit-field 'A' specified here}}
  s->field9 = x;
  s->field10 = (D)x;
  s->field11 = (D)x;
  s->field12 = (D)x;
}

void write_enum_intB(struct S_B *s, int x) {
  s->field1 = (B)x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}}
  // bitfieldwarnings-note@#S_B_field1 {{widen this field to 2 bits to store all values of 'B'}}
  s->field2 = (B)x;
  // bitfieldwarnings-warning@-1 {{signed bit-field 'field2' needs an extra bit to represent the largest positive enumerators of 'B'}}
  // bitfieldwarnings-note@#S_B_field2 {{consider making the bit-field type unsigned}}
  s->field3 = (B)x;
  s->field4 = x;
  // expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}}
  // expected-note@#S_B_field4 {{widen this field to 2 bits to store all values of 'B'}}
  // expected-note@#preferred_S_B_field4 {{preferred type for bit-field 'B' specified here}}
  s->field5 = x;
  s->field6 = x;
  s->field7 = x;
  // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}}
  // expected-note@#S_B_field7 {{widen this field to 2 bits to store all values of 'B'}}
  // expected-note@#preferred_S_B_field7 {{preferred type for bit-field 'B' specified here}}
  s->field8 = x;
  // expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'B'}}
  // expected-note@#S_B_field8 {{consider making the bit-field type unsigned}}
  // expected-note@#preferred_S_B_field8 {{preferred type for bit-field 'B' specified here}}
  s->field9 = x;
  s->field10 = (D)x;
  s->field11 = (D)x;
  s->field12 = (D)x;
}

void write_enum_intC(struct S_C *s, int x) {
  s->field1 = (C)x;
  // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}}
  // bitfieldwarnings-note@#S_C_field1 {{widen this field to 2 bits to store all values of 'C'}}
  s->field2 = (C)x;
  s->field3 = (C)x;
  s->field4 = x;
  // expected-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}}
  // expected-note@#S_C_field4 {{widen this field to 2 bits to store all values of 'C'}}
  // expected-note@#preferred_S_C_field4 {{preferred type for bit-field 'C' specified here}}
  s->field5 = x;
  s->field6 = x;
  s->field7 = x;
  // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}}
  // expected-note@#S_C_field7 {{widen this field to 2 bits to store all values of 'C'}}
  // expected-note@#preferred_S_C_field7 {{preferred type for bit-field 'C' specified here}}
  s->field8 = x;
  // expected-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'C'}}
  // expected-note@#S_C_field8 {{consider making the bit-field type unsigned}}
  // expected-note@#preferred_S_C_field8 {{preferred type for bit-field 'C' specified here}}
  s->field9 = x;
  s->field10 = (D)x;
  s->field11 = (D)x;
  s->field12 = (D)x;
}

void write_low_constantA(S_A *s) {
  s->field1 = A_a;
  s->field2 = A_a;
  s->field3 = A_a;
  s->field4 = A_a;
  s->field5 = A_a;
  s->field6 = A_a;
  s->field7 = A_a;
  s->field8 = A_a;
  s->field9 = A_a;
  s->field10 = (D)A_a;
  s->field11 = (D)A_a;
  s->field12 = (D)A_a;
};

void write_low_constantB(S_B *s) {
  s->field1 = ENUM_CLASS_REF(B, B_a);
  s->field2 = ENUM_CLASS_REF(B, B_a);
  s->field3 = ENUM_CLASS_REF(B, B_a);
  s->field4 = (unsigned)ENUM_CLASS_REF(B, B_a);
  s->field5 = (unsigned)ENUM_CLASS_REF(B, B_a);
  s->field6 = (unsigned)ENUM_CLASS_REF(B, B_a);
  s->field7 = (int)ENUM_CLASS_REF(B, B_a);
  s->field8 = (int)ENUM_CLASS_REF(B, B_a);
  s->field9 = (int)ENUM_CLASS_REF(B, B_a);
  s->field10 = (D)ENUM_CLASS_REF(B, B_a);
  s->field11 = (D)ENUM_CLASS_REF(B, B_a);
  s->field12 = (D)ENUM_CLASS_REF(B, B_a);
};

void write_low_constantC(S_C *s) {
  s->field1 = ENUM_CLASS_REF(C, C_a);
  s->field2 = ENUM_CLASS_REF(C, C_a);
  s->field3 = ENUM_CLASS_REF(C, C_a);
  s->field4 = (unsigned)ENUM_CLASS_REF(C, C_a);
  s->field5 = (unsigned)ENUM_CLASS_REF(C, C_a);
  s->field6 = (unsigned)ENUM_CLASS_REF(C, C_a);
  s->field7 = (int)ENUM_CLASS_REF(C, C_a);
  s->field8 = (int)ENUM_CLASS_REF(C, C_a);
  s->field9 = (int)ENUM_CLASS_REF(C, C_a);
  s->field10 = (D)ENUM_CLASS_REF(C, C_a);
  s->field11 = (D)ENUM_CLASS_REF(C, C_a);
  s->field12 = (D)ENUM_CLASS_REF(C, C_a);
};

void write_high_constantA(S_A *s) {
  s->field1 = A_d;
  // cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to 1}}
  // c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}}
  s->field2 = A_d;
  s->field3 = A_d;
  s->field4 = A_d;
  // cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to 1}}
  // c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}}
  s->field5 = A_d;
  s->field6 = A_d;
  s->field7 = A_d;
  // cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to -1}}
  // c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
  s->field8 = A_d;
  // cpp-warning@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to -1}}
  // c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
  s->field9 = A_d;
  s->field10 = (D)A_d;
  // cpp-warning@-1 {{implicit truncation from 'D' to bit-field changes value from 3 to 1}}
  // c-warning@-2 {{implicit truncation from 'D' (aka 'enum D') to bit-field changes value from 3 to 1}}
  s->field11 = (D)A_d;
  s->field12 = (D)A_d;
};

void write_high_constantB(S_B *s) {
  s->field1 = ENUM_CLASS_REF(B, B_d);
  // cpp-warning@-1 {{implicit truncation from 'B' to bit-field changes value from 3 to 1}}
  // c-warning@-2 {{implicit truncation from 'enum B' to bit-field changes value from 3 to -1}}
  s->field2 = ENUM_CLASS_REF(B, B_d);
  // c-warning@-1 {{implicit truncation from 'enum B' to bit-field changes value from 3 to -1}}
  s->field3 = ENUM_CLASS_REF(B, B_d);
  s->field4 = (unsigned)ENUM_CLASS_REF(B, B_d);
  // expected-warning@-1 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
  s->field5 = (unsigned)ENUM_CLASS_REF(B, B_d);
  s->field6 = (unsigned)ENUM_CLASS_REF(B, B_d);
  s->field7 = (int)ENUM_CLASS_REF(B, B_d);
  // expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
  s->field8 = (int)ENUM_CLASS_REF(B, B_d);
  // expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
  s->field9 = (int)ENUM_CLASS_REF(B, B_d);
};


void write_high_constantC(S_C *s) {
  s->field1 = ENUM_CLASS_REF(C, C_d);
  // cpp-warning@-1 {{implicit truncation from 'C' to bit-field changes value from 3 to 1}}
  // c-warning@-2 {{implicit truncation from 'enum C' to bit-field changes value from 3 to 1}}
  s->field2 = ENUM_CLASS_REF(C, C_d);
  s->field3 = ENUM_CLASS_REF(C, C_d);
  s->field4 = (unsigned)ENUM_CLASS_REF(C, C_d);
  // expected-warning@-1 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
  s->field5 = (unsigned)ENUM_CLASS_REF(C, C_d);
  s->field6 = (unsigned)ENUM_CLASS_REF(C, C_d);
  s->field7 = (int)ENUM_CLASS_REF(C, C_d);
  // expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
  s->field8 = (int)ENUM_CLASS_REF(C, C_d);
  // expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
  s->field9 = (int)ENUM_CLASS_REF(C, C_d);
};
