Add various testcases for checking enum's base & enumerator type. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- validation/enum-base-type.c | 29 +++++++++++++++ validation/enum-bitwise.c | 19 ++++++++++ validation/enum-bounds.c | 24 ++++++++++++ validation/enum-init-constness.c | 9 +++++ validation/enum-invalid.c | 11 ++++++ validation/enum-min-size.c | 30 +++++++++++++++ validation/enum-sign-gcc.c | 63 ++++++++++++++++++++++++++++++++ validation/enum-typecheck.c | 39 ++++++++++++++++++++ 8 files changed, 224 insertions(+) create mode 100644 validation/enum-base-type.c create mode 100644 validation/enum-bitwise.c create mode 100644 validation/enum-bounds.c create mode 100644 validation/enum-init-constness.c create mode 100644 validation/enum-invalid.c create mode 100644 validation/enum-min-size.c create mode 100644 validation/enum-sign-gcc.c create mode 100644 validation/enum-typecheck.c diff --git a/validation/enum-base-type.c b/validation/enum-base-type.c new file mode 100644 index 000000000..ecec59296 --- /dev/null +++ b/validation/enum-base-type.c @@ -0,0 +1,29 @@ +enum n { + NA, + NB = 1L, + NC = 1UL, + ND = 1LL, + NE = 1ULL, + NF = -1, + NG = -1L, + NH = -1LL, +}; +_Static_assert(sizeof(enum n) == sizeof(int), "+-1"); + +enum m { + MA = 0L, + MB = 1L, + MG = -1L, +}; +_Static_assert(sizeof(enum m) == sizeof(int), "+-1L"); + +enum p { + PA = 0UL, + PB = 1UL, +}; +_Static_assert(sizeof(enum p) == sizeof(int), "UL"); + +/* + * check-name: enum-base-type + * check-known-to-fail + */ diff --git a/validation/enum-bitwise.c b/validation/enum-bitwise.c new file mode 100644 index 000000000..fcdb8d7a0 --- /dev/null +++ b/validation/enum-bitwise.c @@ -0,0 +1,19 @@ +#define __bitwise __attribute__((bitwise)) +#define __force __attribute__((force)) + +typedef long long __bitwise bits; + +enum r { + RZ = (__force bits) 0, + RO = (__force bits) 1, + RM = (__force bits) -1, +}; + +_Static_assert([typeof(RZ)] == [bits], "RZ"); +_Static_assert([typeof(RO)] == [bits], "RO"); +_Static_assert([typeof(RM)] == [bits], "RM"); +_Static_assert(sizeof(enum r) == sizeof(bits), "bits"); + +/* + * check-name: enum-bitwise + */ diff --git a/validation/enum-bounds.c b/validation/enum-bounds.c new file mode 100644 index 000000000..d8993edb4 --- /dev/null +++ b/validation/enum-bounds.c @@ -0,0 +1,24 @@ +enum bound_int_max { + IMAX = __INT_MAX__, +}; +_Static_assert([typeof(IMAX)] == [int], ""); + +enum bound_int_maxp1 { + IMP1 = __INT_MAX__ + 1L, +}; +_Static_assert([typeof(IMP1)] == [unsigned int], ""); + +enum bound_int_maxm1 { + IMM1 = -__INT_MAX__ - 1L, +}; +_Static_assert([typeof(IMM1)] == [int], ""); + +enum bound_int_maxm2 { + IMM2 = -__INT_MAX__ - 2L, +}; +_Static_assert([typeof(IMM2)] == [long], ""); + +/* + * check-name: enum-bounds + * check-known-to-fail + */ diff --git a/validation/enum-init-constness.c b/validation/enum-init-constness.c new file mode 100644 index 000000000..5b95bc06a --- /dev/null +++ b/validation/enum-init-constness.c @@ -0,0 +1,9 @@ +extern int invalid; + +enum e { + E = 1 ? 1 : invalid +}; + +/* + * check-name: enum-init-constness + */ diff --git a/validation/enum-invalid.c b/validation/enum-invalid.c new file mode 100644 index 000000000..08846442d --- /dev/null +++ b/validation/enum-invalid.c @@ -0,0 +1,11 @@ +enum e { }; +enum f { F = 0.1 }; + +/* + * check-name: enum-invalid + * + * check-error-start +enum-invalid.c:1:10: error: bad enum definition +enum-invalid.c:2:14: error: bad constant expression + * check-error-end + */ diff --git a/validation/enum-min-size.c b/validation/enum-min-size.c new file mode 100644 index 000000000..264a31542 --- /dev/null +++ b/validation/enum-min-size.c @@ -0,0 +1,30 @@ +enum i { I = 1 }; +_Static_assert(sizeof(enum i) == sizeof(int), "int"); +enum u { U = 1U }; +_Static_assert(sizeof(enum u) == sizeof(int), "uint"); + +enum l { L = 1L }; +_Static_assert(sizeof(enum l) == sizeof(int), "long"); +enum m { M = 1UL }; +_Static_assert(sizeof(enum m) == sizeof(int), "ulong"); + +enum n { N = 1LL }; +_Static_assert(sizeof(enum n) == sizeof(int), "llong"); +enum o { O = 1ULL }; +_Static_assert(sizeof(enum o) == sizeof(int), "ullong"); + + +enum mi { MI = -1 }; +_Static_assert(sizeof(enum i) == sizeof(int), "int"); + +enum ml { ML = -1L }; +_Static_assert(sizeof(enum l) == sizeof(int), "long"); + +enum mn { MN = -1LL }; +_Static_assert(sizeof(enum n) == sizeof(int), "llong"); + + +/* + * check-name: enum-min-size + * check-known-to-fail + */ diff --git a/validation/enum-sign-gcc.c b/validation/enum-sign-gcc.c new file mode 100644 index 000000000..c4779dbe6 --- /dev/null +++ b/validation/enum-sign-gcc.c @@ -0,0 +1,63 @@ +// For enum's underlying/compatible type: +// std C: unspecified +// GCC: 'unsigned int' if no negative values, +// otherwise 'int' (see GCC manul 4.9). +// But also accept ulong, long +// For the type of the enumerators: +// std C: 'int' +// GCC: 'int' if the value fit in a 'int' +// otherwise same as the enum underlying type? +// +// The following tests match GCC's choices + +#define is_unsigned(X) ((typeof(X))-1 > 0) + +enum u { + U = 1U, // fit in 'int' + // no negatives +}; +_Static_assert(sizeof(enum u) == sizeof(int), "size"); +_Static_assert(is_unsigned(enum u), "enum u"); +_Static_assert(is_unsigned(U) == 0, "value U"); // fail + +enum v { + V = __INT_MAX__ + 1U, // doesn't fit in 'int' + // no negatives +}; +_Static_assert(sizeof(enum v) == sizeof(int), "size"); +_Static_assert(is_unsigned(enum v), "enum v"); +_Static_assert(is_unsigned(V) == 1, "value V"); + +enum w { + W = __LONG_MAX__ + 1UL, // doesn't fit in 'long' +}; +_Static_assert(sizeof(enum w) == sizeof(long), "size"); +_Static_assert(is_unsigned(enum w), "enum w"); +_Static_assert(is_unsigned(W) == 1, "value W"); + +enum x { + A = 1, // fit in 'int' + B = 0x100000000UL, // doesn't fit in int +}; +_Static_assert(sizeof(enum x) == sizeof(long), "size"); +_Static_assert(is_unsigned(enum x), "enum x"); +_Static_assert(sizeof(A) == sizeof(int), "size A"); // fail +_Static_assert(is_unsigned(A) == 0, "enum A"); // fail +_Static_assert(sizeof(B) == sizeof(long), "size B"); +_Static_assert(is_unsigned(B) == 1, "enum B"); + +enum y { + C = 1, // fit in 'int' + D = 0x100000000L, // doesn't fit in int +}; +_Static_assert(sizeof(enum y) == sizeof(long), "size"); +_Static_assert(is_unsigned(enum y), "enum y"); +_Static_assert(sizeof(C) == sizeof(int), "size C"); // fail +_Static_assert(is_unsigned(C) == 0, "enum C"); // fail +_Static_assert(sizeof(D) == sizeof(long), "size D"); +_Static_assert(is_unsigned(D) == 1, "enum D"); + +/* + * check-name: enum-sign-gcc + * check-known-to-fail + */ diff --git a/validation/enum-typecheck.c b/validation/enum-typecheck.c new file mode 100644 index 000000000..77b77b47b --- /dev/null +++ b/validation/enum-typecheck.c @@ -0,0 +1,39 @@ +enum good { G, }; +enum bad { B, }; +enum good g; + +enum good compat_int(void) { return 1; } + +void parg(enum good); +void parg(enum bad); + +void farg(enum good a); +void farg(enum bad a) { } + +enum good pret(void); +enum bad pret(void); + +enum good fret(void); +enum bad fret(void) { return 0; } + + +enum good *ptr; +enum bad *ptr; + +enum good *gptr = &g; +enum bad *bptr = &g; + +/* + * check-name: enum-typecheck + * check-command: sparse -Wno-decl $file + * check-known-to-fail + * + * check-error-start +enum-typecheck.c:8:6: error: symbol 'parg' redeclared with different type +enum-typecheck.c:11:6: error: symbol 'farg' redeclared with different type +enum-typecheck.c:14:11: error: symbol 'pret' redeclared with different type +enum-typecheck.c:17:11: error: symbol 'fret' redeclared with different type +enum-typecheck.c:21:12: error: symbol 'ptr' redeclared with different type +enum-typecheck.c:24:20: warning: incorrect type in initializer (different type sizes) + * check-error-end + */ -- 2.18.0