2 test-p99-conformance.c modified from the C conformance test of P99
5 /* This may look like nonsense, but it really is -*- mode: C; coding: utf-8 -*- */
7 /* Except of parts copied from previous work and as explicitly stated below, */
8 /* the author and copyright holder for this work is */
9 /* (C) copyright 2011 Jens Gustedt, INRIA, France */
11 /* This file is free software; it is part of the P99 project. */
12 /* You can redistribute it and/or modify it under the terms of the QPL as */
13 /* given in the file LICENSE. It is distributed without any warranty; */
14 /* without even the implied warranty of merchantability or fitness for a */
15 /* particular purpose. */
20 ** @brief conformance test for C99
22 ** This file only tests the "compiler" part of C, that is without any
23 ** include files. Any C implementation, whether hosted or
24 ** freestanding should comply to this.
26 ** To convince your compiler to compile this you have perhaps to
27 ** provide some additional parameters on the command line. E.g for
28 ** the gcc family of compilers (including third party pretenders) you
29 ** usually have to give "-std=c99" to switch to C99 mode. But other
30 ** parameters may be in order, consult your compiler documentation.
32 ** This file is split into several parts that hopefully are
33 ** self explaining. Each of the parts has a macro @c SKIP_... that
34 ** lets you skip a test.
39 #pragma disable_warning 85
41 #define SKIP_EVALUATED_COMMA_ASSIGN /* Looks like testing for some particular implementation-defined behaviour to me */
43 #ifdef PORT_HOST /* Common GCC issues */
44 # define SKIP_UNIVERSAL_UTF8 /* Only works for GCC when -finput-charset= option is specified */
45 # if (defined (__GNUC__) && __GNUC__ < 5)
46 # define SKIP_UNIVERSAL /* Fails for older GCC (works for me in 6.1.1 but fails on some SDCC build machines*/
47 # define SKIP_INLINE /* fails for some older GCC that is still used on the FreeBSD build machines */
49 #else /* SDCC issues */
50 # define SKIP_HEXDOUBLE /* bug #2536 */
51 # define SKIP_LONG_DOUBLE /* long double not yet supported */
52 # define SKIP_COMPOUND /* compound literals not yet supported */
53 # define SKIP_VLA /* variable-length arrays not supported */
54 # define SKIP_INLINE /* bug #1900 */
55 # define SKIP_PRAGMA /* Standard pragmas not supported */
56 # pragma disable_warning 93 /* Using float for double. */
57 # if defined(__SDCC_pic14) || defined(__SDCC_pic16)
58 # define SKIP_LONG_LONG
62 #ifdef __SDCC_pdk14 // Lack of memory
63 #define SKIP_INITIALIZERS
67 #define SKIP_LONG_LONG
70 #define SKIP_UNIVERSAL
73 #if defined(__SDCC_mcs51) && defined(__SDCC_MODEL_SMALL) // Lack of memory
74 #define SKIP_UNIVERSAL
77 #ifndef SKIP_VA_ARGS_MACRO
78 # define FIRST(X, ...) X
79 # if FIRST(0, something)
80 # error "The preprocessor lacks variable argument list support. Run test with -DSKIP_VA_ARGS_MACRO to be able to see the other tests."
86 enum { hasTrue
= (_Bool
)127, hasFalse
= (_Bool
)0 };
88 _Bool has_Bool
[hasTrue
] = { hasFalse
};
92 double has_VLA_function(unsigned n
, double A
[n
][n
]) {
95 for (i
= 0; i
< n
; ++i
)
96 for (j
= 0; j
< n
; ++j
)
100 double has_VLA(unsigned n
) {
102 return has_VLA_function(n
, VLA
);
109 typedef void (*func
)(void);
111 /* This alone should not result in a generation of a symbol
112 "has_undefined_symbol1". It should even not have an entry as
113 "undefined" in the symbol table, but such an entry would be
117 has_undefined_symbol1(void) {
121 /* This alone should not result in a generation of a symbol
122 "undefined_symbol2" but insert an "undefined" symbol to such a
123 function in the symbol table. */
126 has_undefined_symbol2(void) {
129 func undefined_symbol2_tester
[] = { has_undefined_symbol2
};
131 /* This should result in a generation of a symbol has_mandatory_symbol1 */
134 has_mandatory_symbol1(void) {
139 has_mandatory_symbol1(void);
141 /* This should result in a generation of a symbol has_mandatory_symbol2 */
144 has_mandatory_symbol2(void) {
147 func mandatory_symbol2_tester
[] = { has_mandatory_symbol2
};
150 has_mandatory_symbol2(void);
152 /* This should result in a generation of a symbol has_mandatory_symbol3 */
155 has_mandatory_symbol3(void) {
159 has_mandatory_symbol3(void);
161 /* This should result in a generation of a symbol has_mandatory_symbol4 */
164 has_mandatory_symbol4(void) {
167 func mandatory_symbol4_tester
[] = { has_mandatory_symbol4
};
170 has_mandatory_symbol4(void);
174 #ifndef SKIP_HEXDOUBLE
175 enum { hasHexdouble
= (0x1P
2 > 10) };
176 double has_hexdouble
[hasHexdouble
];
179 #ifndef SKIP_COMPOUND
180 unsigned has_compound_literal(void) {
181 return (unsigned){ 0 };
185 #ifndef SKIP_INITIALIZERS
186 unsigned has_designated_array_initializer
[4] = { [3] = 1u };
187 unsigned A1
[] = { [3] = 1u };
188 unsigned has_length_from_initializer
[sizeof(has_designated_array_initializer
) == sizeof(A1
)];
192 } has_designated_struct_initializer
= { .second
= 1, .first
= 2 };
195 #define GLUE2(A, B) A ## B
196 #define CONCAT2(A, B) GLUE2(A, B)
197 #define STRINGIFY(A) STRINGIFY_(A)
198 #define STRINGIFY_(A) #A
200 #ifndef SKIP_TOKEN_CONCAT
201 double has_concat_of_floats_1E
= CONCAT2(1E
, 3);
202 double has_concat_of_floats_1Ep
= CONCAT2(1E
+, 3);
203 /* This one should iteratively compose a double value from left to
205 # ifndef SKIP_TOKEN_CONCAT_ITERATIVE
206 double has_concat_of_floats_iterative
= CONCAT2(CONCAT2(CONCAT2(1, E
), +), 3);
208 /* These ones are tricky. The terms inside the STRINGIFY should lead to
209 valid preprocessing tokens but which are invalid tokens for the
211 char const has_concat_of_floats_1Ep3Em
[] = STRINGIFY(CONCAT2(CONCAT2(1E
+, 3E
-), 3));
212 # ifndef SKIP_TOKEN_HASH_HASH_AS_ARGUMENT
213 #define DONT_CONCAT_(X) A X B
214 #define DONT_CONCAT(X) DONT_CONCAT_(X)
215 char const has_hash_hash_as_argument
[] = STRINGIFY(DONT_CONCAT(##));
217 # ifndef SKIP_TOKEN_CONCAT_HASH_HASH
218 char const has_concat_of_hash_hash
[] = STRINGIFY(CONCAT2(#, #));
220 # ifndef SKIP_STRINGIFY_EMPTY
221 char const has_stringify_empty
[] = STRINGIFY();
227 /* expand arguments after assigment, but before call */
229 # define GLUE1(X) GLUE2(X)
230 # define CONCAT3(A, B, C) GLUE2(A, B C)
231 # define GLUE3(A, B, C) A ## B ## C
232 unsigned has_determines_macro_arguments_first
[GLUE1(0 COMMA
1)];
234 /* Expand args before ## concatenation? The rules for this are
238 enum { CONCAT2(eat
, GLUE2(EAT
, EAT
)) = GLUE2(EAT
, EAT
),
239 CONCAT2(eat
, CONCAT2(EAT
, EAT
)) = CONCAT2(EAT
, EAT
),
240 /* Only replace the empty argument by a placeholder if it is
241 preceded or followed by a ## in the replacement text. */
242 eat2
= CONCAT3(EAT
,,EAT
),
243 eat3
= GLUE3(EAT
,,EAT
),
245 unsigned has_preprocessor_expands_before_concatenation1
[(eat0
== 0)*2 - 1] = { eat0
};
246 unsigned has_preprocessor_expands_before_concatenation2
[(eat11
== 11)*2 - 1] = { eat0
};
247 unsigned has_preprocessor_no_placeholder_on_recursion
[(eat2
== 11)*2 - 1] = { eat0
};
248 unsigned has_preprocessor_placeholder
[(eat3
== 0)*2 - 1] = { eat0
};
251 #ifndef SKIP_TRAILING_COMMA
252 enum { enumConstant
, } has_enum_trailing_commas
;
253 unsigned has_initializer_trailing_commas
[] = { 0, };
256 #ifndef SKIP_FLEXIBLE
263 char buffer
[sizeof(flexible
) + 2*sizeof(double)];
265 flex2 has_flexible_array
= { .flex
.len
= 2 };
268 #ifndef SKIP_RESTRICT
269 char restrict_buffer
[4];
270 char *restrict has_restrict_keyword
= restrict_buffer
;
273 #ifndef SKIP_STATIC_PARAMETER
274 void has_static_parameter(double A
[static 10]){
278 #ifndef SKIP_CONST_PARAMETER
279 void has_const_parameter(double A
[const 10]){
283 #ifndef SKIP_VOLATILE_PARAMETER
284 void has_volatile_parameter(double A
[volatile 10]){
288 #ifndef SKIP_RESTRICT_PARAMETER
289 # ifndef SKIP_RESTRICT
290 void has_restrict_parameter(double A
[restrict
10]){
296 #ifndef SKIP_COMMENTS
297 enum { hasCppComment
= -2
299 //* for C99 all of this is a comment to the end of the line */ 3
300 /* for C89 this resolves in division by 3 */
302 unsigned has_cpp_comment
[hasCppComment
];
306 unsigned has_mixed_declaration(void) {
307 /* infinite recursion, but who cares */
308 has_mixed_declaration();
314 #ifndef SKIP_FOR_DECLARATION
315 unsigned has_for_declaration(void) {
317 for (unsigned i
= 0; i
< a
; ++i
) {
321 for (unsigned var
; 0;)
332 unsigned const const has_idempotent_const
= 1;
333 unsigned volatile volatile has_idempotent_volatile
= 1;
334 # ifndef SKIP_RESTRICT
335 unsigned *restrict restrict has_idempotent_restrict
= 0;
340 # pragma STDC FP_CONTRACT ON
341 # define PRAGMA(MESS) _Pragma(# MESS)
342 PRAGMA(STDC FP_CONTRACT OFF
)
346 void has_func_macro(char const* where
[]) {
351 #ifndef SKIP_LONG_LONG
352 long long has_long_long
= 0;
353 unsigned long long has_ullong_max
[-1 + 2*((0ULL - 1) >= 18446744073709551615ULL)];
356 #ifndef SKIP_LONG_DOUBLE
357 long double has_long_double
= 1.0L;
360 #ifndef SKIP_PREPRO_ARITH
362 # error "this should be a negative value"
364 unsigned const has_preprocessor_minus
= 1;
366 /* Unsigned arithmetic should be done in the type that corresponds to
367 uintmax_t and it should use modulo arithmetic. */
369 # error "this should be a large positive value"
372 # error "the preprocessor should do modulo arithmetic on unsigned values"
374 unsigned const has_preprocessor_bitneg
= 1;
376 # error "this should be a large positive value, at least UINT_MAX >= 2^{16} - 1"
378 # if (~0U < 4294967295)
379 # error "this should be a large positive value, at least ULONG_MAX >= 2^{32} - 1"
381 # if (~0U < 18446744073709551615ULL)
382 # error "this should be a large positive value, at least ULLONG_MAX >= 2^{64} - 1"
384 unsigned has_preprocessor_uintmax
;
385 # if (1 ? -1 : 0U) < 0
386 # warning "ternary operator should promote to unsigned value"
388 unsigned const has_preprocessor_ternary_unsigned
= 1;
390 # if (1 ? -1 : 0) > 0
391 # warning "ternary operator should result in signed value"
393 unsigned const has_preprocessor_ternary_signed
= 1;
395 /* Bool operation should return a signed integer */
396 # if (1 ? -1 : (0 && 0)) > 0
397 # error "logical operations should return signed values"
399 # if (1 ? -1 : (0U && 0)) > 0
400 # error "logical operations should return signed values"
402 # if (1 ? -1 : (0 && 0U)) > 0
403 # error "logical operations should return signed values"
405 # if (1 ? -1 : (0U && 0U)) > 0
406 # error "logical operations should return signed values"
408 unsigned const has_preprocessor_logical_signed
= 1;
411 /* A comma operator shall not appear in a constant expression, unless
412 it is not evaluated. First test for the good case: it isn't
413 evaluated. First this should be accepted by the compiler but also
414 it should do the correct type promotions. This test can have
415 different results when we try this for constant expressions in the
416 compiler phase or in the preprocessor phase. */
417 #define GOOD ((1 ? -1 : (0, 0u)) < 0 )
418 #ifndef SKIP_NON_EVALUATED_COMMA_ASSIGN
419 unsigned const has_non_evaluated_comma_expression_assign
[2*!GOOD
- 1] = { 0 };
421 #ifndef SKIP_NON_EVALUATED_COMMA_PREPRO
423 # warning "non evaluated comma expression yields wrong result"
425 unsigned const has_non_evaluated_comma_expression_prepro
= GOOD
;
429 /* Now if it is in the evaluated part, this is undefined
430 behavior. This could lead to anything, but also to the nice
431 behavior that the compiler tells us. Some compilers do tell us in
432 fact, but only as a warning. Some just refuse to compile. */
433 #define BAD ((0 ? -1 : (0, 0u)) > -1 )
434 #ifndef SKIP_EVALUATED_COMMA_ASSIGN
437 unsigned const has_evaluated_comma_expression_assign
= 1;
439 #ifndef SKIP_EVALUATED_COMMA_PREPRO
441 # warning "evaluated comma expression yields wrong result"
444 unsigned const has_evaluated_comma_expression_prepro
= 1;
447 #ifndef SKIP_UNIVERSAL
448 int has_hex_character
= L
'\x0401';
449 int has_universal_character_4
= L
'\u2118';
450 int has_universal_character_8
= L
'\U00000401';
451 int const* has_universal_string_4
= L
"\u2018\u03A7\u2060X\u2019";
452 int const* has_universal_string_8
= L
"\U00002018\U000003A7\U00002060X\U00002019";
453 int has_
\u03BA\u03B1\u03B8\u03BF\u03BB\u03B9\u03BA\u03CC\u03C2_
\u03c7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1 = 1;
454 const int \u03BA = 0;
455 int const*const has_keeps_token_boundary_for_universal
= &\u03BA;
456 # ifndef SKIP_UNIVERSAL_MANGLE
457 /* When compiled, the two static variables that are defined here must
458 result in two different symbols. There is no way to check this at
459 compile time, unfortunately. So we have to check the object file
460 by hand to determine this. */
461 int has_universal_good_mangle(int a
) {
462 static int volatile \u03ba;
463 static int volatile _u03ba
;
466 return \u03ba == _u03ba
;
469 int has_universal_bad_mangle
;
471 # ifndef SKIP_UNIVERSAL_UTF8
472 double const π
= 3.14159265;
473 double const* has_utf8
= &π
;
479 /* Have checks for digraphs and trigraphs at the end, since they may
480 mix up the pretty printing. */
484 /* check for the four "language" digraphs */
485 double has_punctuation_digraph
<::> = <% 0 %>;
487 %: define HAS_HASH_DIGRAPH
1
488 enum { hasHashDigraph
= !!HAS_HASH_DIGRAPH
};
489 %: define
DIGRAPH_STRINGIFY(X
) %:X
490 char const has_digraph_stringify
[] = DIGRAPH_STRINGIFY(digraph
);
491 # if !defined(HAS_HASH_DIGRAPH)
492 # error "The preprocessor lacks digraph %: support. Run test with -DSKIP_DIGRAPH to be able to see the other tests."
495 %: define
HAS_HASH_HASH_DIGRAPH_(a
, b
) a
%:%: b
496 %: define HAS_HASH_HASH_DIGRAPH
HAS_HASH_HASH_DIGRAPH_(0, 1)
497 enum { hasHashHashDigraph
= !!HAS_HASH_HASH_DIGRAPH
};
498 /* This one here and the one in the trigraph section should be merged
500 double has_hash_hash_interpretedCorrectly
[hasHashHashDigraph
];
501 # if !defined(HAS_HASH_HASH_DIGRAPH) || (HAS_HASH_HASH_DIGRAPH != 1)
502 # error "The preprocessor lacks quadgraph %:%: support. Run test with -DSKIP_DIGRAPH to be able to see the other tests."
508 #ifndef SKIP_TRIGRAPH
510 /* Check for the eight "language" trigraphs. If this works and you
511 run this through your preprocessor phase (usually with -E) this
512 should, all of a sudden look like valid C code. */
513 int has_punctuation_trigraph
??(??) = ??< (0 ??' 1), (0 ??! 1), ??-0, '??/0' ??>;
514 /* don't get confused by the syntax highlighting the ??' aint't too bad for that */
516 ??= define HAS_HASH_TRIGRAPH
1
517 enum { hasHashTrigraph
= !!HAS_HASH_TRIGRAPH
};
518 ??= define
TRIGRAPH_STRINGIFY(X
) ??=X
519 char const has_trigraph_stringfy
[] = TRIGRAPH_STRINGIFY(trigraph
);
520 # if !defined(HAS_HASH_TRIGRAPH)
521 # error "The preprocessor lacks trigraph ??= support. Run test with -DSKIP_TRIGRAPH to be able to see the other tests."
524 ??= define
HAS_HASH_HASH_TRIGRAPH_(a
, b
) a
??=??= b
525 ??= define HAS_HASH_HASH_TRIGRAPH
HAS_HASH_HASH_TRIGRAPH_(0, 1)
526 enum { hasHashHashTrigraph
= !!HAS_HASH_HASH_TRIGRAPH
};
527 /* This one here and the one in the digraph section should be merged
529 double has_hash_hash_interpretedCorrectly
[hasHashHashTrigraph
];
530 # if !defined(HAS_HASH_HASH_TRIGRAPH) || (HAS_HASH_HASH_TRIGRAPH != 1)
531 # error "The preprocessor lacks hexgraph ??=??= support. Run test with -DSKIP_TRIGRAPH to be able to see the other tests."