1const std = @import("std"); 2const tests = @import("tests.zig"); 3const nl = std.cstr.line_sep; 4 5pub fn addCases(cases: *tests.RunTranslatedCContext) void { 6 cases.add("dereference address of", 7 \\#include <stdlib.h> 8 \\int main(void) { 9 \\ int i = 0; 10 \\ *&i = 42; 11 \\ if (i != 42) abort(); 12 \\ return 0; 13 \\} 14 , ""); 15 16 cases.add("division of floating literals", 17 \\#define _NO_CRT_STDIO_INLINE 1 18 \\#include <stdio.h> 19 \\#define PI 3.14159265358979323846f 20 \\#define DEG2RAD (PI/180.0f) 21 \\int main(void) { 22 \\ printf("DEG2RAD is: %f\n", DEG2RAD); 23 \\ return 0; 24 \\} 25 , "DEG2RAD is: 0.017453" ++ nl); 26 27 cases.add("use global scope for record/enum/typedef type translation if needed", 28 \\void bar(void); 29 \\void baz(void); 30 \\struct foo { int x; }; 31 \\void bar() { 32 \\ struct foo tmp; 33 \\} 34 \\ 35 \\void baz() { 36 \\ struct foo tmp; 37 \\} 38 \\ 39 \\int main(void) { 40 \\ bar(); 41 \\ baz(); 42 \\ return 0; 43 \\} 44 , ""); 45 46 cases.add("failed macros are only declared once", 47 \\#define FOO = 48 \\#define FOO = 49 \\#define PtrToPtr64(p) ((void *POINTER_64) p) 50 \\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s)) 51 \\#define bar = 0x 52 \\#define baz = 0b 53 \\int main(void) {} 54 , ""); 55 56 cases.add("parenthesized string literal", 57 \\void foo(const char *s) {} 58 \\int main(void) { 59 \\ foo(("bar")); 60 \\} 61 , ""); 62 63 cases.add("variable shadowing type type", 64 \\#include <stdlib.h> 65 \\int main() { 66 \\ int type = 1; 67 \\ if (type != 1) abort(); 68 \\} 69 , ""); 70 71 cases.add("assignment as expression", 72 \\#include <stdlib.h> 73 \\int main() { 74 \\ int a, b, c, d = 5; 75 \\ int e = a = b = c = d; 76 \\ if (e != 5) abort(); 77 \\} 78 , ""); 79 80 cases.add("static variable in block scope", 81 \\#include <stdlib.h> 82 \\int foo() { 83 \\ static int bar; 84 \\ bar += 1; 85 \\ return bar; 86 \\} 87 \\int main() { 88 \\ foo(); 89 \\ foo(); 90 \\ if (foo() != 3) abort(); 91 \\} 92 , ""); 93 94 cases.add("array initializer", 95 \\#include <stdlib.h> 96 \\int main(int argc, char **argv) { 97 \\ int a0[4] = {1}; 98 \\ int a1[4] = {1,2,3,4}; 99 \\ int s0 = 0, s1 = 0; 100 \\ for (int i = 0; i < 4; i++) { 101 \\ s0 += a0[i]; 102 \\ s1 += a1[i]; 103 \\ } 104 \\ if (s0 != 1) abort(); 105 \\ if (s1 != 10) abort(); 106 \\} 107 , ""); 108 109 cases.add("forward declarations", 110 \\#include <stdlib.h> 111 \\int foo(int); 112 \\int foo(int x) { return x + 1; } 113 \\int main(int argc, char **argv) { 114 \\ if (foo(2) != 3) abort(); 115 \\ return 0; 116 \\} 117 , ""); 118 119 cases.add("typedef and function pointer", 120 \\#include <stdlib.h> 121 \\typedef struct _Foo Foo; 122 \\typedef int Ret; 123 \\typedef int Param; 124 \\struct _Foo { Ret (*func)(Param p); }; 125 \\static Ret add1(Param p) { 126 \\ return p + 1; 127 \\} 128 \\int main(int argc, char **argv) { 129 \\ Foo strct = { .func = add1 }; 130 \\ if (strct.func(16) != 17) abort(); 131 \\ return 0; 132 \\} 133 , ""); 134 135 cases.add("ternary operator", 136 \\#include <stdlib.h> 137 \\static int cnt = 0; 138 \\int foo() { cnt++; return 42; } 139 \\int main(int argc, char **argv) { 140 \\ short q = 3; 141 \\ signed char z0 = q?:1; 142 \\ if (z0 != 3) abort(); 143 \\ int z1 = 3?:1; 144 \\ if (z1 != 3) abort(); 145 \\ int z2 = foo()?:-1; 146 \\ if (z2 != 42) abort(); 147 \\ if (cnt != 1) abort(); 148 \\ return 0; 149 \\} 150 , ""); 151 152 cases.add("switch case", 153 \\#include <stdlib.h> 154 \\int lottery(unsigned int x) { 155 \\ switch (x) { 156 \\ case 3: return 0; 157 \\ case -1: return 3; 158 \\ case 8 ... 10: return x; 159 \\ default: return -1; 160 \\ } 161 \\} 162 \\int main(int argc, char **argv) { 163 \\ if (lottery(2) != -1) abort(); 164 \\ if (lottery(3) != 0) abort(); 165 \\ if (lottery(-1) != 3) abort(); 166 \\ if (lottery(9) != 9) abort(); 167 \\ return 0; 168 \\} 169 , ""); 170 171 cases.add("boolean values and expressions", 172 \\#include <stdlib.h> 173 \\static const _Bool false_val = 0; 174 \\static const _Bool true_val = 1; 175 \\void foo(int x, int y) { 176 \\ _Bool r = x < y; 177 \\ if (!r) abort(); 178 \\ _Bool self = foo; 179 \\ if (self == false_val) abort(); 180 \\ if (((r) ? 'a' : 'b') != 'a') abort(); 181 \\} 182 \\int main(int argc, char **argv) { 183 \\ foo(2, 5); 184 \\ if (false_val == true_val) abort(); 185 \\ return 0; 186 \\} 187 , ""); 188 189 cases.add("hello world", 190 \\#define _NO_CRT_STDIO_INLINE 1 191 \\#include <stdio.h> 192 \\int main(int argc, char **argv) { 193 \\ printf("hello, world!\n"); 194 \\ return 0; 195 \\} 196 , "hello, world!" ++ nl); 197 198 cases.add("anon struct init", 199 \\#include <stdlib.h> 200 \\struct {int a; int b;} x = {1, 2}; 201 \\int main(int argc, char **argv) { 202 \\ x.a += 2; 203 \\ x.b += 1; 204 \\ if (x.a != 3) abort(); 205 \\ if (x.b != 3) abort(); 206 \\ return 0; 207 \\} 208 , ""); 209 210 cases.add("casting away const and volatile", 211 \\void foo(int *a) {} 212 \\void bar(const int *a) { 213 \\ foo((int *)a); 214 \\} 215 \\void baz(volatile int *a) { 216 \\ foo((int *)a); 217 \\} 218 \\int main(int argc, char **argv) { 219 \\ int a = 0; 220 \\ bar((const int *)&a); 221 \\ baz((volatile int *)&a); 222 \\ return 0; 223 \\} 224 , ""); 225 226 cases.add("anonymous struct & unions", 227 \\#include <stdlib.h> 228 \\#include <stdint.h> 229 \\static struct { struct { uint16_t x, y; }; } x = { 1 }; 230 \\static struct { union { uint32_t x; uint8_t y; }; } y = { 0x55AA55AA }; 231 \\int main(int argc, char **argv) { 232 \\ if (x.x != 1) abort(); 233 \\ if (x.y != 0) abort(); 234 \\ if (y.x != 0x55AA55AA) abort(); 235 \\ if (y.y != 0xAA) abort(); 236 \\ return 0; 237 \\} 238 , ""); 239 240 cases.add("array to pointer decay", 241 \\#include <stdlib.h> 242 \\int main(int argc, char **argv) { 243 \\ char data[3] = {'a','b','c'}; 244 \\ if (2[data] != data[2]) abort(); 245 \\ if ("abc"[1] != data[1]) abort(); 246 \\ char *as_ptr = data; 247 \\ if (2[as_ptr] != as_ptr[2]) abort(); 248 \\ if ("abc"[1] != as_ptr[1]) abort(); 249 \\ return 0; 250 \\} 251 , ""); 252 253 cases.add("struct initializer - packed", 254 \\#define _NO_CRT_STDIO_INLINE 1 255 \\#include <stdint.h> 256 \\#include <stdlib.h> 257 \\struct s {uint8_t x,y; 258 \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; 259 \\int main() { 260 \\ /* sizeof nor offsetof currently supported */ 261 \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); 262 \\ return 0; 263 \\} 264 , ""); 265 266 cases.add("cast signed array index to unsigned", 267 \\#include <stdlib.h> 268 \\int main(int argc, char **argv) { 269 \\ int a[10], i = 0; 270 \\ a[i] = 0; 271 \\ if (a[i] != 0) abort(); 272 \\ return 0; 273 \\} 274 , ""); 275 276 cases.add("cast long long array index to unsigned", 277 \\#include <stdlib.h> 278 \\int main(int argc, char **argv) { 279 \\ long long a[10], i = 0; 280 \\ a[i] = 0; 281 \\ if (a[i] != 0) abort(); 282 \\ return 0; 283 \\} 284 , ""); 285 286 cases.add("case boolean expression converted to int", 287 \\#include <stdlib.h> 288 \\int main(int argc, char **argv) { 289 \\ int value = 1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9; 290 \\ if (value != 4224) abort(); 291 \\ return 0; 292 \\} 293 , ""); 294 295 cases.add("case boolean expression on left converted to int", 296 \\#include <stdlib.h> 297 \\int main(int argc, char **argv) { 298 \\ int value = 8 == 9 | 1 + 2 * 3 + 4 * 5 + 6 << 7; 299 \\ if (value != 4224) abort(); 300 \\ return 0; 301 \\} 302 , ""); 303 304 cases.add("case boolean and operator+ converts bool to int", 305 \\#include <stdlib.h> 306 \\int main(int argc, char **argv) { 307 \\ int value = (8 == 9) + 3; 308 \\ int value2 = 3 + (8 == 9); 309 \\ if (value != value2) abort(); 310 \\ return 0; 311 \\} 312 , ""); 313 314 cases.add("case boolean and operator<", 315 \\#include <stdlib.h> 316 \\int main(int argc, char **argv) { 317 \\ int value = (8 == 9) < 3; 318 \\ if (value == 0) abort(); 319 \\ return 0; 320 \\} 321 , ""); 322 323 cases.add("case boolean and operator*", 324 \\#include <stdlib.h> 325 \\int main(int argc, char **argv) { 326 \\ int value = (8 == 9) * 3; 327 \\ int value2 = 3 * (9 == 9); 328 \\ if (value != 0) abort(); 329 \\ if (value2 == 0) abort(); 330 \\ return 0; 331 \\} 332 , ""); 333 334 cases.add("scoped typedef", 335 \\int main(int argc, char **argv) { 336 \\ typedef int Foo; 337 \\ typedef Foo Bar; 338 \\ typedef void (*func)(int); 339 \\ typedef int uint32_t; 340 \\ uint32_t a; 341 \\ Foo i; 342 \\ Bar j; 343 \\ return 0; 344 \\} 345 , ""); 346 347 cases.add("scoped for loops with shadowing", 348 \\#include <stdlib.h> 349 \\int main() { 350 \\ int count = 0; 351 \\ for (int x = 0; x < 2; x++) 352 \\ for (int x = 0; x < 2; x++) 353 \\ count++; 354 \\ 355 \\ if (count != 4) abort(); 356 \\ return 0; 357 \\} 358 , ""); 359 360 cases.add("array value type casts properly", 361 \\#include <stdlib.h> 362 \\unsigned int choose[53][10]; 363 \\static int hash_binary(int k) 364 \\{ 365 \\ choose[0][k] = 3; 366 \\ int sum = 0; 367 \\ sum += choose[0][k]; 368 \\ return sum; 369 \\} 370 \\ 371 \\int main() { 372 \\ int s = hash_binary(4); 373 \\ if (s != 3) abort(); 374 \\ return 0; 375 \\} 376 , ""); 377 378 cases.add("array value type casts properly use +=", 379 \\#include <stdlib.h> 380 \\static int hash_binary(int k) 381 \\{ 382 \\ unsigned int choose[1][1] = {{3}}; 383 \\ int sum = -1; 384 \\ int prev = 0; 385 \\ prev = sum += choose[0][0]; 386 \\ if (sum != 2) abort(); 387 \\ return sum + prev; 388 \\} 389 \\ 390 \\int main() { 391 \\ int x = hash_binary(4); 392 \\ if (x != 4) abort(); 393 \\ return 0; 394 \\} 395 , ""); 396 397 cases.add("ensure array casts outside +=", 398 \\#include <stdlib.h> 399 \\static int hash_binary(int k) 400 \\{ 401 \\ unsigned int choose[3] = {1, 2, 3}; 402 \\ int sum = -2; 403 \\ int prev = sum + choose[k]; 404 \\ if (prev != 0) abort(); 405 \\ return sum + prev; 406 \\} 407 \\ 408 \\int main() { 409 \\ int x = hash_binary(1); 410 \\ if (x != -2) abort(); 411 \\ return 0; 412 \\} 413 , ""); 414 415 cases.add("array cast int to uint", 416 \\#include <stdlib.h> 417 \\static unsigned int hash_binary(int k) 418 \\{ 419 \\ int choose[3] = {-1, -2, 3}; 420 \\ unsigned int sum = 2; 421 \\ sum += choose[k]; 422 \\ return sum; 423 \\} 424 \\ 425 \\int main() { 426 \\ unsigned int x = hash_binary(1); 427 \\ if (x != 0) abort(); 428 \\ return 0; 429 \\} 430 , ""); 431 432 cases.add("assign enum to uint, no explicit cast", 433 \\#include <stdlib.h> 434 \\typedef enum { 435 \\ ENUM_0 = 0, 436 \\ ENUM_1 = 1, 437 \\} my_enum_t; 438 \\ 439 \\int main() { 440 \\ my_enum_t val = ENUM_1; 441 \\ unsigned int x = val; 442 \\ if (x != 1) abort(); 443 \\ return 0; 444 \\} 445 , ""); 446 447 cases.add("assign enum to int", 448 \\#include <stdlib.h> 449 \\typedef enum { 450 \\ ENUM_0 = 0, 451 \\ ENUM_1 = 1, 452 \\} my_enum_t; 453 \\ 454 \\int main() { 455 \\ my_enum_t val = ENUM_1; 456 \\ int x = val; 457 \\ if (x != 1) abort(); 458 \\ return 0; 459 \\} 460 , ""); 461 462 cases.add("cast enum to smaller uint", 463 \\#include <stdlib.h> 464 \\#include <stdint.h> 465 \\typedef enum { 466 \\ ENUM_0 = 0, 467 \\ ENUM_257 = 257, 468 \\} my_enum_t; 469 \\ 470 \\int main() { 471 \\ my_enum_t val = ENUM_257; 472 \\ uint8_t x = (uint8_t)val; 473 \\ if (x != (uint8_t)257) abort(); 474 \\ return 0; 475 \\} 476 , ""); 477 478 cases.add("cast enum to smaller signed int", 479 \\#include <stdlib.h> 480 \\#include <stdint.h> 481 \\typedef enum { 482 \\ ENUM_0 = 0, 483 \\ ENUM_384 = 384, 484 \\} my_enum_t; 485 \\ 486 \\int main() { 487 \\ my_enum_t val = ENUM_384; 488 \\ int8_t x = (int8_t)val; 489 \\ if (x != (int8_t)384) abort(); 490 \\ return 0; 491 \\} 492 , ""); 493 494 cases.add("cast negative enum to smaller signed int", 495 \\#include <stdlib.h> 496 \\#include <stdint.h> 497 \\typedef enum { 498 \\ ENUM_MINUS_1 = -1, 499 \\ ENUM_384 = 384, 500 \\} my_enum_t; 501 \\ 502 \\int main() { 503 \\ my_enum_t val = ENUM_MINUS_1; 504 \\ int8_t x = (int8_t)val; 505 \\ if (x != -1) abort(); 506 \\ return 0; 507 \\} 508 , ""); 509 510 cases.add("cast negative enum to smaller unsigned int", 511 \\#include <stdlib.h> 512 \\#include <stdint.h> 513 \\typedef enum { 514 \\ ENUM_MINUS_1 = -1, 515 \\ ENUM_384 = 384, 516 \\} my_enum_t; 517 \\ 518 \\int main() { 519 \\ my_enum_t val = ENUM_MINUS_1; 520 \\ uint8_t x = (uint8_t)val; 521 \\ if (x != (uint8_t)-1) abort(); 522 \\ return 0; 523 \\} 524 , ""); 525 526 cases.add("implicit enum cast in boolean expression", 527 \\#include <stdlib.h> 528 \\enum Foo { 529 \\ FooA, 530 \\ FooB, 531 \\ FooC, 532 \\}; 533 \\int main() { 534 \\ int a = 0; 535 \\ float b = 0; 536 \\ void *c = 0; 537 \\ enum Foo d = FooA; 538 \\ if (a || d) abort(); 539 \\ if (d && b) abort(); 540 \\ if (c || d) abort(); 541 \\ return 0; 542 \\} 543 , ""); 544 545 cases.add("issue #6707 cast builtin call result to opaque struct pointer", 546 \\#include <stdlib.h> 547 \\struct foo* make_foo(void) 548 \\{ 549 \\ return (struct foo*)__builtin_strlen("0123456789ABCDEF"); 550 \\} 551 \\int main(void) { 552 \\ struct foo *foo_pointer = make_foo(); 553 \\ if (foo_pointer != (struct foo*)16) abort(); 554 \\ return 0; 555 \\} 556 , ""); 557 558 cases.add("C built-ins", 559 \\#include <stdlib.h> 560 \\#include <limits.h> 561 \\#include <stdbool.h> 562 \\#define M_E 2.71828182845904523536 563 \\#define M_PI_2 1.57079632679489661923 564 \\bool check_clz(unsigned int pos) { 565 \\ return (__builtin_clz(1 << pos) == (8 * sizeof(unsigned int) - pos - 1)); 566 \\} 567 \\int main(void) { 568 \\ if (__builtin_bswap16(0x0102) != 0x0201) abort(); 569 \\ if (__builtin_bswap32(0x01020304) != 0x04030201) abort(); 570 \\ if (__builtin_bswap64(0x0102030405060708) != 0x0807060504030201) abort(); 571 \\ 572 \\ if (__builtin_signbit(0.0) != 0) abort(); 573 \\ if (__builtin_signbitf(0.0f) != 0) abort(); 574 \\ if (__builtin_signbit(1.0) != 0) abort(); 575 \\ if (__builtin_signbitf(1.0f) != 0) abort(); 576 \\ if (__builtin_signbit(-1.0) != 1) abort(); 577 \\ if (__builtin_signbitf(-1.0f) != 1) abort(); 578 \\ 579 \\ if (__builtin_popcount(0) != 0) abort(); 580 \\ if (__builtin_popcount(0b1) != 1) abort(); 581 \\ if (__builtin_popcount(0b11) != 2) abort(); 582 \\ if (__builtin_popcount(0b1111) != 4) abort(); 583 \\ if (__builtin_popcount(0b11111111) != 8) abort(); 584 \\ 585 \\ if (__builtin_ctz(0b1) != 0) abort(); 586 \\ if (__builtin_ctz(0b10) != 1) abort(); 587 \\ if (__builtin_ctz(0b100) != 2) abort(); 588 \\ if (__builtin_ctz(0b10000) != 4) abort(); 589 \\ if (__builtin_ctz(0b100000000) != 8) abort(); 590 \\ 591 \\ if (!check_clz(0)) abort(); 592 \\ if (!check_clz(1)) abort(); 593 \\ if (!check_clz(2)) abort(); 594 \\ if (!check_clz(4)) abort(); 595 \\ if (!check_clz(8)) abort(); 596 \\ 597 \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256))) != 2.0) abort(); 598 \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0))) != 2.0) abort(); 599 \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0f))) != 2.0) abort(); 600 \\ if (__builtin_sqrtf(__builtin_sqrtf(__builtin_sqrtf(256.0f))) != 2.0f) abort(); 601 \\ 602 \\ if (__builtin_sin(1.0) != -__builtin_sin(-1.0)) abort(); 603 \\ if (__builtin_sinf(1.0f) != -__builtin_sinf(-1.0f)) abort(); 604 \\ if (__builtin_sin(M_PI_2) != 1.0) abort(); 605 \\ if (__builtin_sinf(M_PI_2) != 1.0f) abort(); 606 \\ 607 \\ if (__builtin_cos(1.0) != __builtin_cos(-1.0)) abort(); 608 \\ if (__builtin_cosf(1.0f) != __builtin_cosf(-1.0f)) abort(); 609 \\ if (__builtin_cos(0.0) != 1.0) abort(); 610 \\ if (__builtin_cosf(0.0f) != 1.0f) abort(); 611 \\ 612 \\ if (__builtin_exp(0) != 1.0) abort(); 613 \\ if (__builtin_fabs(__builtin_exp(1.0) - M_E) > 0.00000001) abort(); 614 \\ if (__builtin_exp(0.0f) != 1.0f) abort(); 615 \\ 616 \\ if (__builtin_exp2(0) != 1.0) abort(); 617 \\ if (__builtin_exp2(4.0) != 16.0) abort(); 618 \\ if (__builtin_exp2f(0.0f) != 1.0f) abort(); 619 \\ if (__builtin_exp2f(4.0f) != 16.0f) abort(); 620 \\ 621 \\ if (__builtin_log(M_E) != 1.0) abort(); 622 \\ if (__builtin_log(1.0) != 0.0) abort(); 623 \\ if (__builtin_logf(1.0f) != 0.0f) abort(); 624 \\ 625 \\ if (__builtin_log2(8.0) != 3.0) abort(); 626 \\ if (__builtin_log2(1.0) != 0.0) abort(); 627 \\ if (__builtin_log2f(8.0f) != 3.0f) abort(); 628 \\ if (__builtin_log2f(1.0f) != 0.0f) abort(); 629 \\ 630 \\ if (__builtin_log10(1000.0) != 3.0) abort(); 631 \\ if (__builtin_log10(1.0) != 0.0) abort(); 632 \\ if (__builtin_log10f(1000.0f) != 3.0f) abort(); 633 \\ if (__builtin_log10f(1.0f) != 0.0f) abort(); 634 \\ 635 \\ if (__builtin_fabs(-42.0f) != 42.0) abort(); 636 \\ if (__builtin_fabs(-42.0) != 42.0) abort(); 637 \\ if (__builtin_fabs(-42) != 42.0) abort(); 638 \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort(); 639 \\ 640 \\ if (__builtin_fabs(-42.0f) != 42.0) abort(); 641 \\ if (__builtin_fabs(-42.0) != 42.0) abort(); 642 \\ if (__builtin_fabs(-42) != 42.0) abort(); 643 \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort(); 644 \\ 645 \\ if (__builtin_abs(42) != 42) abort(); 646 \\ if (__builtin_abs(-42) != 42) abort(); 647 \\ if (__builtin_abs(INT_MIN) != INT_MIN) abort(); 648 \\ 649 \\ if (__builtin_floor(42.9) != 42.0) abort(); 650 \\ if (__builtin_floor(-42.9) != -43.0) abort(); 651 \\ if (__builtin_floorf(42.9f) != 42.0f) abort(); 652 \\ if (__builtin_floorf(-42.9f) != -43.0f) abort(); 653 \\ 654 \\ if (__builtin_ceil(42.9) != 43.0) abort(); 655 \\ if (__builtin_ceil(-42.9) != -42) abort(); 656 \\ if (__builtin_ceilf(42.9f) != 43.0f) abort(); 657 \\ if (__builtin_ceilf(-42.9f) != -42.0f) abort(); 658 \\ 659 \\ if (__builtin_trunc(42.9) != 42.0) abort(); 660 \\ if (__builtin_truncf(42.9f) != 42.0f) abort(); 661 \\ if (__builtin_trunc(-42.9) != -42.0) abort(); 662 \\ if (__builtin_truncf(-42.9f) != -42.0f) abort(); 663 \\ 664 \\ if (__builtin_round(0.5) != 1.0) abort(); 665 \\ if (__builtin_round(-0.5) != -1.0) abort(); 666 \\ if (__builtin_roundf(0.5f) != 1.0f) abort(); 667 \\ if (__builtin_roundf(-0.5f) != -1.0f) abort(); 668 \\ 669 \\ if (__builtin_strcmp("abc", "abc") != 0) abort(); 670 \\ if (__builtin_strcmp("abc", "def") >= 0 ) abort(); 671 \\ if (__builtin_strcmp("def", "abc") <= 0) abort(); 672 \\ 673 \\ if (__builtin_strlen("this is a string") != 16) abort(); 674 \\ 675 \\ char *s = malloc(6); 676 \\ __builtin_memcpy(s, "hello", 5); 677 \\ s[5] = '\0'; 678 \\ if (__builtin_strlen(s) != 5) abort(); 679 \\ 680 \\ __builtin_memset(s, 42, __builtin_strlen(s)); 681 \\ if (s[0] != 42 || s[1] != 42 || s[2] != 42 || s[3] != 42 || s[4] != 42) abort(); 682 \\ 683 \\ free(s); 684 \\ 685 \\ return 0; 686 \\} 687 , ""); 688 689 cases.add("function macro that uses builtin", 690 \\#include <stdlib.h> 691 \\#define FOO(x, y) (__builtin_popcount((x)) + __builtin_strlen((y))) 692 \\int main() { 693 \\ if (FOO(7, "hello!") != 9) abort(); 694 \\ return 0; 695 \\} 696 , ""); 697 698 cases.add("assign bool result to int or char", 699 \\#include <stdlib.h> 700 \\#include <stdbool.h> 701 \\bool foo() { return true; } 702 \\int main() { 703 \\ int x = foo(); 704 \\ if (x != 1) abort(); 705 \\ signed char c = foo(); 706 \\ if (c != 1) abort(); 707 \\ return 0; 708 \\} 709 , ""); 710 711 cases.add("static K&R-style no prototype function declaration (empty parameter list)", 712 \\#include <stdlib.h> 713 \\static int foo() { 714 \\ return 42; 715 \\} 716 \\int main() { 717 \\ if (foo() != 42) abort(); 718 \\ return 0; 719 \\} 720 , ""); 721 722 cases.add("K&R-style static function prototype for unused function", 723 \\static int foo(); 724 \\int main() { 725 \\ return 0; 726 \\} 727 , ""); 728 729 cases.add("K&R-style static function prototype + separate definition", 730 \\#include <stdlib.h> 731 \\static int foo(); 732 \\static int foo(int a, int b) { 733 \\ return a + b; 734 \\} 735 \\int main() { 736 \\ if (foo(40, 2) != 42) abort(); 737 \\ return 0; 738 \\} 739 , ""); 740 741 cases.add("dollar sign in identifiers", 742 \\#include <stdlib.h> 743 \\#define $FOO 2 744 \\#define $foo bar$ 745 \\#define $baz($x) ($x + $FOO) 746 \\int $$$(int $x$) { return $x$ + $FOO; } 747 \\int main() { 748 \\ int bar$ = 42; 749 \\ if ($foo != 42) abort(); 750 \\ if (bar$ != 42) abort(); 751 \\ if ($baz(bar$) != 44) abort(); 752 \\ if ($$$(bar$) != 44) abort(); 753 \\ return 0; 754 \\} 755 , ""); 756 757 cases.add("Cast boolean expression result to int", 758 \\#include <stdlib.h> 759 \\char foo(char c) { return c; } 760 \\int bar(int i) { return i; } 761 \\long baz(long l) { return l; } 762 \\int main() { 763 \\ if (foo(1 == 2)) abort(); 764 \\ if (!foo(1 == 1)) abort(); 765 \\ if (bar(1 == 2)) abort(); 766 \\ if (!bar(1 == 1)) abort(); 767 \\ if (baz(1 == 2)) abort(); 768 \\ if (!baz(1 == 1)) abort(); 769 \\ return 0; 770 \\} 771 , ""); 772 773 cases.add("Wide, UTF-16, and UTF-32 character literals", 774 \\#include <wchar.h> 775 \\#include <stdlib.h> 776 \\int main() { 777 \\ wchar_t wc = L'™'; 778 \\ int utf16_char = u'™'; 779 \\ int utf32_char = U''; 780 \\ if (wc != 8482) abort(); 781 \\ if (utf16_char != 8482) abort(); 782 \\ if (utf32_char != 128175) abort(); 783 \\ unsigned char c = wc; 784 \\ if (c != 0x22) abort(); 785 \\ c = utf32_char; 786 \\ if (c != 0xaf) abort(); 787 \\ return 0; 788 \\} 789 , ""); 790 791 cases.add("Variadic function call", 792 \\#define _NO_CRT_STDIO_INLINE 1 793 \\#include <stdio.h> 794 \\int main(void) { 795 \\ printf("%d %d\n", 1, 2); 796 \\ return 0; 797 \\} 798 , "1 2" ++ nl); 799 800 cases.add("multi-character character constant", 801 \\#include <stdlib.h> 802 \\int main(void) { 803 \\ int foo = 'abcd'; 804 \\ switch (foo) { 805 \\ case 'abcd': break; 806 \\ default: abort(); 807 \\ } 808 \\ return 0; 809 \\} 810 , ""); 811 812 cases.add("Array initializers (string literals, incomplete arrays)", 813 \\#include <stdlib.h> 814 \\#include <string.h> 815 \\extern int foo[]; 816 \\int global_arr[] = {1, 2, 3}; 817 \\char global_string[] = "hello"; 818 \\int main(int argc, char *argv[]) { 819 \\ if (global_arr[2] != 3) abort(); 820 \\ if (strlen(global_string) != 5) abort(); 821 \\ const char *const_str = "hello"; 822 \\ if (strcmp(const_str, "hello") != 0) abort(); 823 \\ char empty_str[] = ""; 824 \\ if (strlen(empty_str) != 0) abort(); 825 \\ char hello[] = "hello"; 826 \\ if (strlen(hello) != 5 || sizeof(hello) != 6) abort(); 827 \\ int empty[] = {}; 828 \\ if (sizeof(empty) != 0) abort(); 829 \\ int bar[] = {42}; 830 \\ if (bar[0] != 42) abort(); 831 \\ bar[0] = 43; 832 \\ if (bar[0] != 43) abort(); 833 \\ int baz[] = {1, [42] = 123, 456}; 834 \\ if (baz[42] != 123 || baz[43] != 456) abort(); 835 \\ if (sizeof(baz) != sizeof(int) * 44) abort(); 836 \\ const char *const names[] = {"first", "second", "third"}; 837 \\ if (strcmp(names[2], "third") != 0) abort(); 838 \\ char catted_str[] = "abc" "def"; 839 \\ if (strlen(catted_str) != 6 || sizeof(catted_str) != 7) abort(); 840 \\ char catted_trunc_str[2] = "abc" "def"; 841 \\ if (sizeof(catted_trunc_str) != 2 || catted_trunc_str[0] != 'a' || catted_trunc_str[1] != 'b') abort(); 842 \\ char big_array_utf8lit[10] = ""; 843 \\ if (strcmp(big_array_utf8lit, "") != 0 || big_array_utf8lit[9] != 0) abort(); 844 \\ return 0; 845 \\} 846 , ""); 847 848 cases.add("Wide, UTF-16, and UTF-32 string literals", 849 \\#include <stdlib.h> 850 \\#include <stdint.h> 851 \\#include <wchar.h> 852 \\int main(void) { 853 \\ const wchar_t *wide_str = L"wide"; 854 \\ const wchar_t wide_hello[] = L"hello"; 855 \\ if (wcslen(wide_str) != 4) abort(); 856 \\ if (wcslen(L"literal") != 7) abort(); 857 \\ if (wcscmp(wide_hello, L"hello") != 0) abort(); 858 \\ 859 \\ const uint16_t *u16_str = u"wide"; 860 \\ const uint16_t u16_hello[] = u"hello"; 861 \\ if (u16_str[3] != u'e' || u16_str[4] != 0) abort(); 862 \\ if (u16_hello[4] != u'o' || u16_hello[5] != 0) abort(); 863 \\ 864 \\ const uint32_t *u32_str = U"wide"; 865 \\ const uint32_t u32_hello[] = U"hello"; 866 \\ if (u32_str[3] != U'e' || u32_str[4] != 0) abort(); 867 \\ if (u32_hello[4] != U'o' || u32_hello[5] != 0) abort(); 868 \\ return 0; 869 \\} 870 , ""); 871 872 cases.add("Address of function is no-op", 873 \\#include <stdlib.h> 874 \\#include <stdbool.h> 875 \\typedef int (*myfunc)(int); 876 \\int a(int arg) { return arg + 1;} 877 \\int b(int arg) { return arg + 2;} 878 \\int caller(myfunc fn, int arg) { 879 \\ return fn(arg); 880 \\} 881 \\int main() { 882 \\ myfunc arr[3] = {&a, &b, a}; 883 \\ myfunc foo = a; 884 \\ myfunc bar = &(a); 885 \\ if (foo != bar) abort(); 886 \\ if (arr[0] == arr[1]) abort(); 887 \\ if (arr[0] != arr[2]) abort(); 888 \\ if (caller(b, 40) != 42) abort(); 889 \\ if (caller(&b, 40) != 42) abort(); 890 \\ return 0; 891 \\} 892 , ""); 893 894 cases.add("Obscure ways of calling functions; issue #4124", 895 \\#include <stdlib.h> 896 \\static int add(int a, int b) { 897 \\ return a + b; 898 \\} 899 \\typedef int (*adder)(int, int); 900 \\typedef void (*funcptr)(void); 901 \\int main() { 902 \\ if ((add)(1, 2) != 3) abort(); 903 \\ if ((&add)(1, 2) != 3) abort(); 904 \\ if (add(3, 1) != 4) abort(); 905 \\ if ((*add)(2, 3) != 5) abort(); 906 \\ if ((**add)(7, -1) != 6) abort(); 907 \\ if ((***add)(-2, 9) != 7) abort(); 908 \\ 909 \\ int (*ptr)(int a, int b); 910 \\ ptr = add; 911 \\ 912 \\ if (ptr(1, 2) != 3) abort(); 913 \\ if ((*ptr)(3, 1) != 4) abort(); 914 \\ if ((**ptr)(2, 3) != 5) abort(); 915 \\ if ((***ptr)(7, -1) != 6) abort(); 916 \\ if ((****ptr)(-2, 9) != 7) abort(); 917 \\ 918 \\ funcptr addr1 = (funcptr)(add); 919 \\ funcptr addr2 = (funcptr)(&add); 920 \\ 921 \\ if (addr1 != addr2) abort(); 922 \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort(); 923 \\ if (((adder)addr2)(1, 2) != 3) abort(); 924 \\ return 0; 925 \\} 926 , ""); 927 928 cases.add("Return boolean expression as int; issue #6215", 929 \\#include <stdlib.h> 930 \\#include <stdbool.h> 931 \\bool actual_bool(void) { return 4 - 1 < 4;} 932 \\char char_bool_ret(void) { return 0 || 1; } 933 \\short short_bool_ret(void) { return 0 < 1; } 934 \\int int_bool_ret(void) { return 1 && 1; } 935 \\long long_bool_ret(void) { return !(0 > 1); } 936 \\static int GLOBAL = 1; 937 \\int nested_scopes(int a, int b) { 938 \\ if (a == 1) { 939 \\ int target = 1; 940 \\ return b == target; 941 \\ } else { 942 \\ int target = 2; 943 \\ if (b == target) { 944 \\ return GLOBAL == 1; 945 \\ } 946 \\ return target == 2; 947 \\ } 948 \\} 949 \\int main(void) { 950 \\ if (!actual_bool()) abort(); 951 \\ if (!char_bool_ret()) abort(); 952 \\ if (!short_bool_ret()) abort(); 953 \\ if (!int_bool_ret()) abort(); 954 \\ if (!long_bool_ret()) abort(); 955 \\ if (!nested_scopes(1, 1)) abort(); 956 \\ if (nested_scopes(1, 2)) abort(); 957 \\ if (!nested_scopes(0, 2)) abort(); 958 \\ if (!nested_scopes(0, 3)) abort(); 959 \\ return 1 != 1; 960 \\} 961 , ""); 962 963 cases.add("Comma operator should create new scope; issue #7989", 964 \\#include <stdlib.h> 965 \\#include <stdio.h> 966 \\int main(void) { 967 \\ if (1 || (abort(), 1)) {} 968 \\ if (0 && (1, printf("do not print\n"))) {} 969 \\ int x = 0; 970 \\ x = (x = 3, 4, x + 1); 971 \\ if (x != 4) abort(); 972 \\ return 0; 973 \\} 974 , ""); 975 976 cases.add("Use correct break label for statement expression in nested scope", 977 \\#include <stdlib.h> 978 \\int main(void) { 979 \\ int x = ({1, ({2; 3;});}); 980 \\ if (x != 3) abort(); 981 \\ return 0; 982 \\} 983 , ""); 984 985 cases.add("pointer difference: scalar array w/ size truncation or negative result. Issue #7216", 986 \\#include <stdlib.h> 987 \\#include <stddef.h> 988 \\#define SIZE 10 989 \\int main() { 990 \\ int foo[SIZE]; 991 \\ int *start = &foo[0]; 992 \\ int *one_past_end = start + SIZE; 993 \\ ptrdiff_t diff = one_past_end - start; 994 \\ char diff_char = one_past_end - start; 995 \\ if (diff != SIZE || diff_char != SIZE) abort(); 996 \\ diff = start - one_past_end; 997 \\ if (diff != -SIZE) abort(); 998 \\ if (one_past_end - foo != SIZE) abort(); 999 \\ if ((one_past_end - 1) - foo != SIZE - 1) abort(); 1000 \\ if ((start + 1) - foo != 1) abort(); 1001 \\ return 0; 1002 \\} 1003 , ""); 1004 1005 // C standard: if the expression P points either to an element of an array object or one 1006 // past the last element of an array object, and the expression Q points to the last 1007 // element of the same array object, the expression ((Q)+1)-(P) has the same value as 1008 // ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points 1009 // one past the last element of the array object, even though the expression (Q)+1 1010 // does not point to an element of the array object 1011 cases.add("pointer difference: C standard edge case", 1012 \\#include <stdlib.h> 1013 \\#include <stddef.h> 1014 \\#define SIZE 10 1015 \\int main() { 1016 \\ int foo[SIZE]; 1017 \\ int *start = &foo[0]; 1018 \\ int *P = start + SIZE; 1019 \\ int *Q = &foo[SIZE - 1]; 1020 \\ if ((Q + 1) - P != 0) abort(); 1021 \\ if ((Q + 1) - P != (Q - P) + 1) abort(); 1022 \\ if ((Q + 1) - P != -(P - (Q + 1))) abort(); 1023 \\ return 0; 1024 \\} 1025 , ""); 1026 1027 cases.add("pointer difference: unary operators", 1028 \\#include <stdlib.h> 1029 \\int main() { 1030 \\ int foo[10]; 1031 \\ int *x = &foo[1]; 1032 \\ const int *y = &foo[5]; 1033 \\ if (y - x++ != 4) abort(); 1034 \\ if (y - x != 3) abort(); 1035 \\ if (y - ++x != 2) abort(); 1036 \\ if (y - x-- != 2) abort(); 1037 \\ if (y - x != 3) abort(); 1038 \\ if (y - --x != 4) abort(); 1039 \\ if (y - &foo[0] != 5) abort(); 1040 \\ return 0; 1041 \\} 1042 , ""); 1043 1044 cases.add("pointer difference: struct array with padding", 1045 \\#include <stdlib.h> 1046 \\#include <stddef.h> 1047 \\#define SIZE 10 1048 \\typedef struct my_struct { 1049 \\ int x; 1050 \\ char c; 1051 \\ int y; 1052 \\} my_struct_t; 1053 \\int main() { 1054 \\ my_struct_t foo[SIZE]; 1055 \\ my_struct_t *start = &foo[0]; 1056 \\ my_struct_t *one_past_end = start + SIZE; 1057 \\ ptrdiff_t diff = one_past_end - start; 1058 \\ int diff_int = one_past_end - start; 1059 \\ if (diff != SIZE || diff_int != SIZE) abort(); 1060 \\ diff = start - one_past_end; 1061 \\ if (diff != -SIZE) abort(); 1062 \\ return 0; 1063 \\} 1064 , ""); 1065 1066 cases.add("pointer difference: array of function pointers", 1067 \\#include <stdlib.h> 1068 \\int a(void) { return 1;} 1069 \\int b(void) { return 2;} 1070 \\int c(void) { return 3;} 1071 \\typedef int (*myfunc)(void); 1072 \\int main() { 1073 \\ myfunc arr[] = {a, b, c, a, b, c}; 1074 \\ myfunc *f1 = &arr[1]; 1075 \\ myfunc *f4 = &arr[4]; 1076 \\ if (f4 - f1 != 3) abort(); 1077 \\ return 0; 1078 \\} 1079 , ""); 1080 1081 cases.add("typeof operator", 1082 \\#include <stdlib.h> 1083 \\static int FOO = 42; 1084 \\typedef typeof(FOO) foo_type; 1085 \\typeof(foo_type) myfunc(typeof(FOO) x) { return (typeof(FOO)) x; } 1086 \\int main(void) { 1087 \\ int x = FOO; 1088 \\ typeof(x) y = x; 1089 \\ foo_type z = y; 1090 \\ if (x != y) abort(); 1091 \\ if (myfunc(z) != x) abort(); 1092 \\ 1093 \\ const char *my_string = "bar"; 1094 \\ typeof (typeof (my_string)[4]) string_arr = {"a","b","c","d"}; 1095 \\ if (string_arr[0][0] != 'a' || string_arr[3][0] != 'd') abort(); 1096 \\ return 0; 1097 \\} 1098 , ""); 1099 1100 cases.add("offsetof", 1101 \\#include <stddef.h> 1102 \\#include <stdlib.h> 1103 \\#define container_of(ptr, type, member) ({ \ 1104 \\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 1105 \\ (type *)( (char *)__mptr - offsetof(type,member) );}) 1106 \\typedef struct { 1107 \\ int i; 1108 \\ struct { int x; char y; int z; } s; 1109 \\ float f; 1110 \\} container; 1111 \\int main(void) { 1112 \\ if (offsetof(container, i) != 0) abort(); 1113 \\ if (offsetof(container, s) <= offsetof(container, i)) abort(); 1114 \\ if (offsetof(container, f) <= offsetof(container, s)) abort(); 1115 \\ 1116 \\ container my_container; 1117 \\ typeof(my_container.s) *inner_member_pointer = &my_container.s; 1118 \\ float *float_member_pointer = &my_container.f; 1119 \\ int *anon_member_pointer = &my_container.s.z; 1120 \\ container *my_container_p; 1121 \\ 1122 \\ my_container_p = container_of(inner_member_pointer, container, s); 1123 \\ if (my_container_p != &my_container) abort(); 1124 \\ 1125 \\ my_container_p = container_of(float_member_pointer, container, f); 1126 \\ if (my_container_p != &my_container) abort(); 1127 \\ 1128 \\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort(); 1129 \\ return 0; 1130 \\} 1131 , ""); 1132 1133 cases.add("handle assert.h", 1134 \\#include <assert.h> 1135 \\int main() { 1136 \\ int x = 1; 1137 \\ int *xp = &x; 1138 \\ assert(1); 1139 \\ assert(x != 0); 1140 \\ assert(xp); 1141 \\ assert(*xp); 1142 \\ return 0; 1143 \\} 1144 , ""); 1145 1146 cases.add("NDEBUG disables assert", 1147 \\#define NDEBUG 1148 \\#include <assert.h> 1149 \\int main() { 1150 \\ assert(0); 1151 \\ assert(NULL); 1152 \\ return 0; 1153 \\} 1154 , ""); 1155 1156 cases.add("pointer arithmetic with signed operand", 1157 \\#include <stdlib.h> 1158 \\int main() { 1159 \\ int array[10]; 1160 \\ int *x = &array[5]; 1161 \\ int *y; 1162 \\ int idx = 0; 1163 \\ y = x + ++idx; 1164 \\ if (y != x + 1 || y != &array[6]) abort(); 1165 \\ y = idx + x; 1166 \\ if (y != x + 1 || y != &array[6]) abort(); 1167 \\ y = x - idx; 1168 \\ if (y != x - 1 || y != &array[4]) abort(); 1169 \\ 1170 \\ idx = 0; 1171 \\ y = --idx + x; 1172 \\ if (y != x - 1 || y != &array[4]) abort(); 1173 \\ y = idx + x; 1174 \\ if (y != x - 1 || y != &array[4]) abort(); 1175 \\ y = x - idx; 1176 \\ if (y != x + 1 || y != &array[6]) abort(); 1177 \\ 1178 \\ idx = 1; 1179 \\ x += idx; 1180 \\ if (x != &array[6]) abort(); 1181 \\ x -= idx; 1182 \\ if (x != &array[5]) abort(); 1183 \\ y = (x += idx); 1184 \\ if (y != x || y != &array[6]) abort(); 1185 \\ y = (x -= idx); 1186 \\ if (y != x || y != &array[5]) abort(); 1187 \\ 1188 \\ if (array + idx != &array[1] || array + 1 != &array[1]) abort(); 1189 \\ idx = -1; 1190 \\ if (array - idx != &array[1]) abort(); 1191 \\ 1192 \\ return 0; 1193 \\} 1194 , ""); 1195 1196 cases.add("Compound literals", 1197 \\#include <stdlib.h> 1198 \\struct Foo { 1199 \\ int a; 1200 \\ char b[2]; 1201 \\ float c; 1202 \\}; 1203 \\int main() { 1204 \\ struct Foo foo; 1205 \\ int x = 1, y = 2; 1206 \\ foo = (struct Foo) {x + y, {'a', 'b'}, 42.0f}; 1207 \\ if (foo.a != x + y || foo.b[0] != 'a' || foo.b[1] != 'b' || foo.c != 42.0f) abort(); 1208 \\ return 0; 1209 \\} 1210 , ""); 1211 1212 cases.add("Generic selections", 1213 \\#include <stdlib.h> 1214 \\#include <string.h> 1215 \\#include <stdint.h> 1216 \\#define my_generic_fn(X) _Generic((X), \ 1217 \\ int: abs, \ 1218 \\ char *: strlen, \ 1219 \\ size_t: malloc, \ 1220 \\ default: free \ 1221 \\)(X) 1222 \\#define my_generic_val(X) _Generic((X), \ 1223 \\ int: 1, \ 1224 \\ const char *: "bar" \ 1225 \\) 1226 \\int main(void) { 1227 \\ if (my_generic_val(100) != 1) abort(); 1228 \\ 1229 \\ const char *foo = "foo"; 1230 \\ const char *bar = my_generic_val(foo); 1231 \\ if (strcmp(bar, "bar") != 0) abort(); 1232 \\ 1233 \\ if (my_generic_fn(-42) != 42) abort(); 1234 \\ if (my_generic_fn("hello") != 5) abort(); 1235 \\ 1236 \\ size_t size = 8192; 1237 \\ uint8_t *mem = my_generic_fn(size); 1238 \\ memset(mem, 42, size); 1239 \\ if (mem[size - 1] != 42) abort(); 1240 \\ my_generic_fn(mem); 1241 \\ 1242 \\ return 0; 1243 \\} 1244 , ""); 1245 1246 // See __builtin_alloca_with_align comment in std.zig.c_builtins 1247 cases.add("use of unimplemented builtin in unused function does not prevent compilation", 1248 \\#include <stdlib.h> 1249 \\void unused() { 1250 \\ __builtin_alloca_with_align(1, 8); 1251 \\} 1252 \\int main(void) { 1253 \\ if (__builtin_sqrt(1.0) != 1.0) abort(); 1254 \\ return 0; 1255 \\} 1256 , ""); 1257 1258 cases.add("convert single-statement bodies into blocks for if/else/for/while. issue #8159", 1259 \\#include <stdlib.h> 1260 \\int foo() { return 1; } 1261 \\int main(void) { 1262 \\ int i = 0; 1263 \\ if (i == 0) if (i == 0) if (i != 0) i = 1; 1264 \\ if (i != 0) i = 1; else if (i == 0) if (i == 0) i += 1; 1265 \\ for (; i < 10;) for (; i < 10;) i++; 1266 \\ while (i == 100) while (i == 100) foo(); 1267 \\ if (0) do do "string"; while(1); while(1); 1268 \\ return 0; 1269 \\} 1270 , ""); 1271 1272 cases.add("cast RHS of compound assignment if necessary, unused result", 1273 \\#include <stdlib.h> 1274 \\int main(void) { 1275 \\ signed short val = -1; 1276 \\ val += 1; if (val != 0) abort(); 1277 \\ val -= 1; if (val != -1) abort(); 1278 \\ val *= 2; if (val != -2) abort(); 1279 \\ val /= 2; if (val != -1) abort(); 1280 \\ val %= 2; if (val != -1) abort(); 1281 \\ val <<= 1; if (val != -2) abort(); 1282 \\ val >>= 1; if (val != -1) abort(); 1283 \\ val += 100000000; // compile error if @truncate() not inserted 1284 \\ unsigned short uval = 1; 1285 \\ uval += 1; if (uval != 2) abort(); 1286 \\ uval -= 1; if (uval != 1) abort(); 1287 \\ uval *= 2; if (uval != 2) abort(); 1288 \\ uval /= 2; if (uval != 1) abort(); 1289 \\ uval %= 2; if (uval != 1) abort(); 1290 \\ uval <<= 1; if (uval != 2) abort(); 1291 \\ uval >>= 1; if (uval != 1) abort(); 1292 \\ uval += 100000000; // compile error if @truncate() not inserted 1293 \\} 1294 , ""); 1295 1296 cases.add("cast RHS of compound assignment if necessary, used result", 1297 \\#include <stdlib.h> 1298 \\int main(void) { 1299 \\ signed short foo; 1300 \\ signed short val = -1; 1301 \\ foo = (val += 1); if (foo != 0) abort(); 1302 \\ foo = (val -= 1); if (foo != -1) abort(); 1303 \\ foo = (val *= 2); if (foo != -2) abort(); 1304 \\ foo = (val /= 2); if (foo != -1) abort(); 1305 \\ foo = (val %= 2); if (foo != -1) abort(); 1306 \\ foo = (val <<= 1); if (foo != -2) abort(); 1307 \\ foo = (val >>= 1); if (foo != -1) abort(); 1308 \\ foo = (val += 100000000); // compile error if @truncate() not inserted 1309 \\ unsigned short ufoo; 1310 \\ unsigned short uval = 1; 1311 \\ ufoo = (uval += 1); if (ufoo != 2) abort(); 1312 \\ ufoo = (uval -= 1); if (ufoo != 1) abort(); 1313 \\ ufoo = (uval *= 2); if (ufoo != 2) abort(); 1314 \\ ufoo = (uval /= 2); if (ufoo != 1) abort(); 1315 \\ ufoo = (uval %= 2); if (ufoo != 1) abort(); 1316 \\ ufoo = (uval <<= 1); if (ufoo != 2) abort(); 1317 \\ ufoo = (uval >>= 1); if (ufoo != 1) abort(); 1318 \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted 1319 \\} 1320 , ""); 1321 1322 cases.add("basic vector expressions", 1323 \\#include <stdlib.h> 1324 \\#include <stdint.h> 1325 \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); 1326 \\int main(int argc, char**argv) { 1327 \\ __v8hi uninitialized; 1328 \\ __v8hi empty_init = {}; 1329 \\ __v8hi partial_init = {0, 1, 2, 3}; 1330 \\ 1331 \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7}; 1332 \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800}; 1333 \\ 1334 \\ __v8hi sum = a + b; 1335 \\ for (int i = 0; i < 8; i++) { 1336 \\ if (sum[i] != a[i] + b[i]) abort(); 1337 \\ } 1338 \\ return 0; 1339 \\} 1340 , ""); 1341 1342 cases.add("__builtin_shufflevector", 1343 \\#include <stdlib.h> 1344 \\#include <stdint.h> 1345 \\typedef int16_t __v4hi __attribute__((__vector_size__(8))); 1346 \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); 1347 \\int main(int argc, char**argv) { 1348 \\ __v8hi v8_a = {0, 1, 2, 3, 4, 5, 6, 7}; 1349 \\ __v8hi v8_b = {100, 200, 300, 400, 500, 600, 700, 800}; 1350 \\ __v8hi shuffled = __builtin_shufflevector(v8_a, v8_b, 0, 1, 2, 3, 8, 9, 10, 11); 1351 \\ for (int i = 0; i < 8; i++) { 1352 \\ if (i < 4) { 1353 \\ if (shuffled[i] != v8_a[i]) abort(); 1354 \\ } else { 1355 \\ if (shuffled[i] != v8_b[i - 4]) abort(); 1356 \\ } 1357 \\ } 1358 \\ shuffled = __builtin_shufflevector( 1359 \\ (__v8hi) {-1, -1, -1, -1, -1, -1, -1, -1}, 1360 \\ (__v8hi) {42, 42, 42, 42, 42, 42, 42, 42}, 1361 \\ 0, 1, 2, 3, 8, 9, 10, 11 1362 \\ ); 1363 \\ for (int i = 0; i < 8; i++) { 1364 \\ if (i < 4) { 1365 \\ if (shuffled[i] != -1) abort(); 1366 \\ } else { 1367 \\ if (shuffled[i] != 42) abort(); 1368 \\ } 1369 \\ } 1370 \\ __v4hi shuffled_to_fewer_elements = __builtin_shufflevector(v8_a, v8_b, 0, 1, 8, 9); 1371 \\ for (int i = 0; i < 4; i++) { 1372 \\ if (i < 2) { 1373 \\ if (shuffled_to_fewer_elements[i] != v8_a[i]) abort(); 1374 \\ } else { 1375 \\ if (shuffled_to_fewer_elements[i] != v8_b[i - 2]) abort(); 1376 \\ } 1377 \\ } 1378 \\ __v4hi v4_a = {0, 1, 2, 3}; 1379 \\ __v4hi v4_b = {100, 200, 300, 400}; 1380 \\ __v8hi shuffled_to_more_elements = __builtin_shufflevector(v4_a, v4_b, 0, 1, 2, 3, 4, 5, 6, 7); 1381 \\ for (int i = 0; i < 4; i++) { 1382 \\ if (shuffled_to_more_elements[i] != v4_a[i]) abort(); 1383 \\ if (shuffled_to_more_elements[i + 4] != v4_b[i]) abort(); 1384 \\ } 1385 \\ return 0; 1386 \\} 1387 , ""); 1388 1389 cases.add("__builtin_convertvector", 1390 \\#include <stdlib.h> 1391 \\#include <stdint.h> 1392 \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); 1393 \\typedef uint16_t __v8hu __attribute__((__vector_size__(16))); 1394 \\int main(int argc, char**argv) { 1395 \\ __v8hi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4}; 1396 \\ __v8hu unsigned_vector = __builtin_convertvector(signed_vector, __v8hu); 1397 \\ 1398 \\ for (int i = 0; i < 8; i++) { 1399 \\ if (unsigned_vector[i] != (uint16_t)signed_vector[i]) abort(); 1400 \\ } 1401 \\ return 0; 1402 \\} 1403 , ""); 1404 1405 cases.add("vector casting", 1406 \\#include <stdlib.h> 1407 \\#include <stdint.h> 1408 \\typedef int8_t __v8qi __attribute__((__vector_size__(8))); 1409 \\typedef uint8_t __v8qu __attribute__((__vector_size__(8))); 1410 \\int main(int argc, char**argv) { 1411 \\ __v8qi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4}; 1412 \\ 1413 \\ uint64_t big_int = (uint64_t) signed_vector; 1414 \\ if (big_int != 0x01020304FFFEFDFCULL && big_int != 0xFCFDFEFF04030201ULL) abort(); 1415 \\ __v8qu unsigned_vector = (__v8qu) big_int; 1416 \\ for (int i = 0; i < 8; i++) { 1417 \\ if (unsigned_vector[i] != (uint8_t)signed_vector[i] && unsigned_vector[i] != (uint8_t)signed_vector[7 - i]) abort(); 1418 \\ } 1419 \\ return 0; 1420 \\} 1421 , ""); 1422 1423 cases.add("break from switch statement. Issue #8387", 1424 \\#include <stdlib.h> 1425 \\int switcher(int x) { 1426 \\ switch (x) { 1427 \\ case 0: // no braces 1428 \\ x += 1; 1429 \\ break; 1430 \\ case 1: // conditional break 1431 \\ if (x == 1) { 1432 \\ x += 1; 1433 \\ break; 1434 \\ } 1435 \\ x += 100; 1436 \\ case 2: { // braces with fallthrough 1437 \\ x += 1; 1438 \\ } 1439 \\ case 3: // fallthrough to return statement 1440 \\ x += 1; 1441 \\ case 42: { // random out of order case 1442 \\ x += 1; 1443 \\ return x; 1444 \\ } 1445 \\ case 4: { // break within braces 1446 \\ x += 1; 1447 \\ break; 1448 \\ } 1449 \\ case 5: 1450 \\ x += 1; // fallthrough to default 1451 \\ default: 1452 \\ x += 1; 1453 \\ } 1454 \\ return x; 1455 \\} 1456 \\int main(void) { 1457 \\ int expected[] = {1, 2, 5, 5, 5, 7, 7}; 1458 \\ for (int i = 0; i < sizeof(expected) / sizeof(int); i++) { 1459 \\ int res = switcher(i); 1460 \\ if (res != expected[i]) abort(); 1461 \\ } 1462 \\ if (switcher(42) != 43) abort(); 1463 \\ return 0; 1464 \\} 1465 , ""); 1466 1467 cases.add("Cast to enum from larger integral type. Issue #6011", 1468 \\#include <stdint.h> 1469 \\#include <stdlib.h> 1470 \\enum Foo { A, B, C }; 1471 \\static inline enum Foo do_stuff(void) { 1472 \\ int64_t i = 1; 1473 \\ return (enum Foo)i; 1474 \\} 1475 \\int main(void) { 1476 \\ if (do_stuff() != B) abort(); 1477 \\ return 0; 1478 \\} 1479 , ""); 1480 1481 cases.add("Render array LHS as grouped node if necessary", 1482 \\#include <stdlib.h> 1483 \\int main(void) { 1484 \\ int arr[] = {40, 41, 42, 43}; 1485 \\ if ((arr + 1)[1] != 42) abort(); 1486 \\ return 0; 1487 \\} 1488 , ""); 1489 1490 cases.add("typedef with multiple names", 1491 \\#include <stdlib.h> 1492 \\typedef struct { 1493 \\ char field; 1494 \\} a_t, b_t; 1495 \\ 1496 \\int main(void) { 1497 \\ a_t a = { .field = 42 }; 1498 \\ b_t b = a; 1499 \\ if (b.field != 42) abort(); 1500 \\ return 0; 1501 \\} 1502 , ""); 1503 1504 cases.add("__cleanup__ attribute", 1505 \\#include <stdlib.h> 1506 \\static int cleanup_count = 0; 1507 \\void clean_up(int *final_value) { 1508 \\ if (*final_value != cleanup_count++) abort(); 1509 \\} 1510 \\void doit(void) { 1511 \\ int a __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 2; 1512 \\ int b __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 1; 1513 \\ int c __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 0; 1514 \\} 1515 \\int main(void) { 1516 \\ doit(); 1517 \\ if (cleanup_count != 3) abort(); 1518 \\ return 0; 1519 \\} 1520 , ""); 1521 1522 cases.add("enum used as boolean expression", 1523 \\#include <stdlib.h> 1524 \\enum FOO {BAR, BAZ}; 1525 \\int main(void) { 1526 \\ enum FOO x = BAR; 1527 \\ if (x) abort(); 1528 \\ if (!BAZ) abort(); 1529 \\ return 0; 1530 \\} 1531 , ""); 1532 1533 cases.add("Flexible arrays", 1534 \\#include <stdlib.h> 1535 \\#include <stdint.h> 1536 \\typedef struct { char foo; int bar; } ITEM; 1537 \\typedef struct { size_t count; ITEM items[]; } ITEM_LIST; 1538 \\typedef struct { unsigned char count; int items[]; } INT_LIST; 1539 \\#define SIZE 10 1540 \\int main(void) { 1541 \\ ITEM_LIST *list = malloc(sizeof(ITEM_LIST) + SIZE * sizeof(ITEM)); 1542 \\ for (int i = 0; i < SIZE; i++) list->items[i] = (ITEM) {.foo = i, .bar = i + 1}; 1543 \\ const ITEM_LIST *const c_list = list; 1544 \\ for (int i = 0; i < SIZE; i++) if (c_list->items[i].foo != i || c_list->items[i].bar != i + 1) abort(); 1545 \\ INT_LIST *int_list = malloc(sizeof(INT_LIST) + SIZE * sizeof(int)); 1546 \\ for (int i = 0; i < SIZE; i++) int_list->items[i] = i; 1547 \\ const INT_LIST *const c_int_list = int_list; 1548 \\ const int *const ints = int_list->items; 1549 \\ for (int i = 0; i < SIZE; i++) if (ints[i] != i) abort(); 1550 \\ return 0; 1551 \\} 1552 , ""); 1553 1554 cases.add("enum with value that fits in c_uint but not c_int, issue #8003", 1555 \\#include <stdlib.h> 1556 \\enum my_enum { 1557 \\ FORCE_UINT = 0xffffffff 1558 \\}; 1559 \\int main(void) { 1560 \\ if(FORCE_UINT != 0xffffffff) abort(); 1561 \\} 1562 , ""); 1563 1564 cases.add("block-scope static variable shadows function parameter. Issue #8208", 1565 \\#include <stdlib.h> 1566 \\int func1(int foo) { return foo + 1; } 1567 \\int func2(void) { 1568 \\ static int foo = 5; 1569 \\ return foo++; 1570 \\} 1571 \\int main(void) { 1572 \\ if (func1(42) != 43) abort(); 1573 \\ if (func2() != 5) abort(); 1574 \\ if (func2() != 6) abort(); 1575 \\ return 0; 1576 \\} 1577 , ""); 1578 1579 cases.add("nested same-name static locals", 1580 \\#include <stdlib.h> 1581 \\int func(int val) { 1582 \\ static int foo; 1583 \\ if (foo != val) abort(); 1584 \\ { 1585 \\ foo += 1; 1586 \\ static int foo = 2; 1587 \\ if (foo != val + 2) abort(); 1588 \\ foo += 1; 1589 \\ } 1590 \\ return foo; 1591 \\} 1592 \\int main(void) { 1593 \\ int foo = 1; 1594 \\ if (func(0) != 1) abort(); 1595 \\ if (func(1) != 2) abort(); 1596 \\ if (func(2) != 3) abort(); 1597 \\ if (foo != 1) abort(); 1598 \\ return 0; 1599 \\} 1600 , ""); 1601 1602 cases.add("Enum constants are assigned correct type. Issue #9153", 1603 \\enum A { A0, A1=0xFFFFFFFF }; 1604 \\enum B { B0=-1, B1=0xFFFFFFFF }; 1605 \\enum C { C0=-1, C1=0 }; 1606 \\enum D { D0, D1=0xFFFFFFFFFFL }; 1607 \\enum E { E0=-1, E1=0xFFFFFFFFFFL }; 1608 \\int main(void) { 1609 \\ signed char a0 = A0, a1 = A1; 1610 \\ signed char b0 = B0, b1 = B1; 1611 \\ signed char c0 = C0, c1 = C1; 1612 \\ signed char d0 = D0, d1 = D1; 1613 \\ signed char e0 = E0, e1 = E1; 1614 \\ return 0; 1615 \\} 1616 , ""); 1617 1618 cases.add("Enum constant matches enum name; multiple enumerations with same value", 1619 \\#include <stdlib.h> 1620 \\enum FOO { 1621 \\ FOO = 1, 1622 \\ BAR = 2, 1623 \\ BAZ = 1, 1624 \\}; 1625 \\int main(void) { 1626 \\ enum FOO x = BAZ; 1627 \\ if (x != 1) abort(); 1628 \\ if (x != BAZ) abort(); 1629 \\ if (x != FOO) abort(); 1630 \\} 1631 , ""); 1632 1633 cases.add("Scoped enums", 1634 \\#include <stdlib.h> 1635 \\int main(void) { 1636 \\ enum Foo { A, B, C }; 1637 \\ enum Foo a = B; 1638 \\ if (a != B) abort(); 1639 \\ if (a != 1) abort(); 1640 \\ { 1641 \\ enum Foo { A = 5, B = 6, C = 7 }; 1642 \\ enum Foo a = B; 1643 \\ if (a != B) abort(); 1644 \\ if (a != 6) abort(); 1645 \\ } 1646 \\ if (a != B) abort(); 1647 \\ if (a != 1) abort(); 1648 \\} 1649 , ""); 1650 1651 cases.add("Underscore identifiers", 1652 \\#include <stdlib.h> 1653 \\int _ = 10; 1654 \\typedef struct { int _; } S; 1655 \\int main(void) { 1656 \\ if (_ != 10) abort(); 1657 \\ S foo = { ._ = _ }; 1658 \\ if (foo._ != _) abort(); 1659 \\ return 0; 1660 \\} 1661 , ""); 1662 1663 cases.add("__builtin_choose_expr (unchosen expression is not evaluated)", 1664 \\#include <stdlib.h> 1665 \\int main(void) { 1666 \\ int x = 0.0; 1667 \\ int y = 0.0; 1668 \\ int res; 1669 \\ res = __builtin_choose_expr(1, 1, x / y); 1670 \\ if (res != 1) abort(); 1671 \\ res = __builtin_choose_expr(0, x / y, 2); 1672 \\ if (res != 2) abort(); 1673 \\ return 0; 1674 \\} 1675 , ""); 1676 1677 // TODO: add isnan check for long double once bitfield support is added 1678 // (needed for x86_64-windows-gnu) 1679 // TODO: add isinf check for long double once std.math.isInf supports c_longdouble 1680 cases.add("NAN and INFINITY", 1681 \\#include <math.h> 1682 \\#include <stdint.h> 1683 \\#include <stdlib.h> 1684 \\union uf { uint32_t u; float f; }; 1685 \\#define CHECK_NAN(STR, VAL) { \ 1686 \\ union uf unpack = {.f = __builtin_nanf(STR)}; \ 1687 \\ if (!isnan(unpack.f)) abort(); \ 1688 \\ if (unpack.u != VAL) abort(); \ 1689 \\} 1690 \\int main(void) { 1691 \\ float f_nan = NAN; 1692 \\ if (!isnan(f_nan)) abort(); 1693 \\ double d_nan = NAN; 1694 \\ if (!isnan(d_nan)) abort(); 1695 \\ CHECK_NAN("0", 0x7FC00000); 1696 \\ CHECK_NAN("", 0x7FC00000); 1697 \\ CHECK_NAN("1", 0x7FC00001); 1698 \\ CHECK_NAN("0x7FC00000", 0x7FC00000); 1699 \\ CHECK_NAN("0x7FC0000F", 0x7FC0000F); 1700 \\ CHECK_NAN("0x7FC000F0", 0x7FC000F0); 1701 \\ CHECK_NAN("0x7FC00F00", 0x7FC00F00); 1702 \\ CHECK_NAN("0x7FC0F000", 0x7FC0F000); 1703 \\ CHECK_NAN("0x7FCF0000", 0x7FCF0000); 1704 \\ CHECK_NAN("0xFFFFFFFF", 0x7FFFFFFF); 1705 \\ float f_inf = INFINITY; 1706 \\ if (!isinf(f_inf)) abort(); 1707 \\ double d_inf = INFINITY; 1708 \\ if (!isinf(d_inf)) abort(); 1709 \\ return 0; 1710 \\} 1711 , ""); 1712 1713 cases.add("signed array subscript. Issue #8556", 1714 \\#include <stdint.h> 1715 \\#include <stdlib.h> 1716 \\#define TEST_NEGATIVE(type) { type x = -1; if (ptr[x] != 42) abort(); } 1717 \\#define TEST_UNSIGNED(type) { type x = 2; if (arr[x] != 42) abort(); } 1718 \\int main(void) { 1719 \\ int arr[] = {40, 41, 42, 43}; 1720 \\ int *ptr = arr + 3; 1721 \\ if (ptr[-1] != 42) abort(); 1722 \\ TEST_NEGATIVE(int); 1723 \\ TEST_NEGATIVE(long); 1724 \\ TEST_NEGATIVE(long long); 1725 \\ TEST_NEGATIVE(int64_t); 1726 \\ TEST_NEGATIVE(__int128); 1727 \\ TEST_UNSIGNED(unsigned); 1728 \\ TEST_UNSIGNED(unsigned long); 1729 \\ TEST_UNSIGNED(unsigned long long); 1730 \\ TEST_UNSIGNED(uint64_t); 1731 \\ TEST_UNSIGNED(size_t); 1732 \\ TEST_UNSIGNED(unsigned __int128); 1733 \\ return 0; 1734 \\} 1735 , ""); 1736 1737 cases.add("Ensure side-effects only evaluated once for signed array indices", 1738 \\#include <stdlib.h> 1739 \\int main(void) { 1740 \\ int foo[] = {1, 2, 3, 4}; 1741 \\ int *p = foo; 1742 \\ int idx = 1; 1743 \\ if ((++p)[--idx] != 2) abort(); 1744 \\ if (p != foo + 1) abort(); 1745 \\ if (idx != 0) abort(); 1746 \\ if ((p++)[idx++] != 2) abort(); 1747 \\ if (p != foo + 2) abort(); 1748 \\ if (idx != 1) abort(); 1749 \\ return 0; 1750 \\} 1751 , ""); 1752 1753 cases.add("Allow non-const char* string literals. Issue #9126", 1754 \\#include <stdlib.h> 1755 \\int func(char *x) { return x[0]; } 1756 \\struct S { char *member; }; 1757 \\struct S global_struct = { .member = "global" }; 1758 \\char *g = "global"; 1759 \\int main(void) { 1760 \\ if (g[0] != 'g') abort(); 1761 \\ if (global_struct.member[0] != 'g') abort(); 1762 \\ char *string = "hello"; 1763 \\ if (string[0] != 'h') abort(); 1764 \\ struct S s = {.member = "hello"}; 1765 \\ if (s.member[0] != 'h') abort(); 1766 \\ if (func("foo") != 'f') abort(); 1767 \\ return 0; 1768 \\} 1769 , ""); 1770 1771 cases.add("Ensure while loop under an if doesn't steal the else. Issue #9953", 1772 \\#include <stdio.h> 1773 \\void doWork(int id) { } 1774 \\int reallyDelete(int id) { printf("deleted %d\n", id); return 1; } 1775 \\int process(int id, int n, int delete) { 1776 \\ if(!delete) 1777 \\ while(n-- > 0) doWork(id); 1778 \\ else 1779 \\ return reallyDelete(id); 1780 \\ return 0; 1781 \\} 1782 \\int main(void) { 1783 \\ process(99, 3, 0); 1784 \\ return 0; 1785 \\} 1786 , ""); 1787 1788 cases.add("Remainder operator with negative integers. Issue #10176", 1789 \\#include <stdlib.h> 1790 \\int main(void) { 1791 \\ int denominator = -2; 1792 \\ int numerator = 5; 1793 \\ if (numerator % denominator != 1) abort(); 1794 \\ numerator = -5; denominator = 2; 1795 \\ if (numerator % denominator != -1) abort(); 1796 \\ return 0; 1797 \\} 1798 , ""); 1799 1800 cases.add("Boolean expression coerced to int. Issue #10175", 1801 \\#include <stdlib.h> 1802 \\int sign(int v) { 1803 \\ return -(v < 0); 1804 \\} 1805 \\int main(void) { 1806 \\ if (sign(-5) != -1) abort(); 1807 \\ if (sign(5) != 0) abort(); 1808 \\ if (sign(0) != 0) abort(); 1809 \\ return 0; 1810 \\} 1811 , ""); 1812} 1813