diff options
Diffstat (limited to 'tests')
82 files changed, 4018 insertions, 437 deletions
diff --git a/tests/Makefile b/tests/Makefile index 5f6777d..0b74fbc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -12,6 +12,7 @@ TESTS = \ hello-exe \ hello-run \ libtest \ + libtest_mt \ test3 \ memtest \ dlltest \ @@ -22,21 +23,30 @@ TESTS = \ tests2-dir \ pp-dir -BTESTS = test1b test3b btest - -# test4 -- problem with -static +BTESTS = btest test1b +# test4_static -- Not all relocation types are implemented yet. # asmtest / asmtest2 -- minor differences with gcc -# btest -- works on i386 (including win32) -# bounds-checking is supported only on i386 -ifneq ($(ARCH),i386) - TESTS := $(filter-out $(BTESTS),$(TESTS)) +# bounds-checking is supported on i386 and x86_64 on linux and windows +ifeq (-$(CONFIG_musl)-, --) +ifeq ($(ARCH),i386) + TESTS += $(BTESTS) +endif +ifeq ($(ARCH),x86_64) + TESTS += $(BTESTS) +endif +ifeq ($(ARCH),arm) + TESTS += $(BTESTS) +endif +ifeq ($(ARCH),arm64) + TESTS += $(BTESTS) endif -ifdef CONFIG_WIN32 - TESTS := $(filter-out $(BTESTS),$(TESTS)) +ifeq ($(ARCH),riscv64) + TESTS += $(BTESTS) endif -ifdef CONFIG_OSX # -run only - TESTS := hello-run libtest tests2-dir pp-dir +endif +ifdef CONFIG_OSX # some don't work yet + TESTS := $(filter-out dlltest, $(TESTS)) endif ifeq (,$(filter arm64 i386 x86_64,$(ARCH))) TESTS := $(filter-out vla_test-run,$(TESTS)) @@ -47,19 +57,42 @@ endif ifeq (,$(filter i386 x86_64,$(ARCH))) TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS)) endif -ifndef CONFIG_cross - TESTS := $(filter-out cross-%,$(TESTS)) -endif ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll - PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH) + PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH) +endif + +ifdef CONFIG_OSX +LIBS += $(LINK_LIBTCC) +endif + + +ifeq ($(ARCH),arm) +# tcctest refers to the alignment of functions, and with thumb mode +# the low bit of code addresses selects the mode, so the "alignment" +# of functions via bit masking comes out as 1. Just disable thumb. +test.ref: CFLAGS+=-marm +endif +ifeq ($(ARCH),i386) +# tcctest.c:get_asm_string uses a construct that is checked too strictly +# by GCC in 32bit mode when PIC is enabled. +test.ref: CFLAGS+=-fno-PIC -fno-PIE +endif +ifeq ($(CC_NAME),msvc) +test.ref abitest : CC = gcc endif RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) DISAS = objdump -d +ifdef CONFIG_OSX +DUMPTCC = (set -x; $(TOP)/tcc -vv; otool -L $(TOP)/tcc; exit 1) +else DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1) +endif -all test : clean-s $(TESTS) +all test : + @$(MAKE) --no-print-directory -s clean + @$(MAKE) --no-print-directory -s -r $(TESTS) hello-exe: ../examples/ex1.c @echo ------------ $@ ------------ @@ -69,13 +102,16 @@ hello-run: ../examples/ex1.c @echo ------------ $@ ------------ $(TCC) -run $< || $(DUMPTCC) -libtest: libtcc_test$(EXESUF) +libtes%: libtcc_tes%$(EXESUF) @echo ------------ $@ ------------ - ./libtcc_test$(EXESUF) $(TCCFLAGS) + ./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) libtcc_test$(EXESUF): libtcc_test.c $(LIBTCC) $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +libtcc_test_mt$(EXESUF): libtcc_test_mt.c $(LIBTCC) + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + %-dir: @echo ------------ $@ ------------ $(MAKE) -k -C $* @@ -88,22 +124,24 @@ test.ref: tcctest.c # auto test test1 test1b: tcctest.c test.ref @echo ------------ $@ ------------ - $(TCC) -run $< > test.out1 - @diff -u test.ref test.out1 && echo "Auto Test OK" + $(TCC) $(RUN_TCC) -w -run $< > test.out1 + @diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK" # iterated test2 (compile tcc then compile tcctest.c !) test2 test2b: tcctest.c test.ref @echo ------------ $@ ------------ - $(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2 - @diff -u test.ref test.out2 && echo "Auto Test2 OK" + $(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2 + @diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK" # iterated test3 (compile tcc then compile tcc then compile tcctest.c !) test3 test3b: tcctest.c test.ref @echo ------------ $@ ------------ - $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3 - @diff -u test.ref test.out3 && echo "Auto Test3 OK" + $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3 + @diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK" -test%b : TCCFLAGS += -b +AUTO_TEST = Auto Test +test%b : TCCFLAGS += -b -bt1 +test%b : AUTO_TEST = Auto Bound-Test # binary output test test4: tcctest.c test.ref @@ -112,19 +150,22 @@ test4: tcctest.c test.ref $(TCC) -c -o tcctest3.o $< $(TCC) -o tcctest3 tcctest3.o ./tcctest3 > test3.out - @if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi + @if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi # dynamic output $(TCC) -o tcctest1 $< ./tcctest1 > test1.out - @if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi + @if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi # dynamic output + bound check $(TCC) -b -o tcctest4 $< ./tcctest4 > test4.out - @if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi -# static output + @if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi + +test4_static: tcctest.c test.ref + @echo ------------ $@ ------------ +# static output. $(TCC) -static -o tcctest2 $< ./tcctest2 > test2.out - @if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi + @if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi # use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them dlltest: @@ -145,32 +186,30 @@ memtest: @echo ------------ $@ ------------ $(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF) ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS) - ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c - + ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c + @echo OK # memory and bound check auto test -BOUNDS_OK = 1 4 8 10 14 -BOUNDS_FAIL= 2 5 7 9 11 12 13 15 +BOUNDS_OK = 1 4 8 10 14 16 +BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17 18 btest: boundtest.c @echo ------------ $@ ------------ @for i in $(BOUNDS_OK); do \ - echo ; echo --- boundtest $$i ---; \ - if $(TCC) -b -run $< $$i ; then \ - echo succeeded as expected; \ + if $(TCC) -b -run $< $$i >/dev/null 2>&1 ; then \ + echo "Test $$i succeeded as expected" ; \ else\ - echo Failed positive test $$i ; exit 1 ; \ + echo "Failed positive test $$i" ; exit 1 ; \ fi ;\ done ;\ for i in $(BOUNDS_FAIL); do \ - echo ; echo --- boundtest $$i ---; \ - if $(TCC) -b -run $< $$i ; then \ - echo Failed negative test $$i ; exit 1 ;\ + if $(TCC) -b -bt1 -run $< $$i >/dev/null 2>&1 ; then \ + echo "Failed negative test $$i" ; exit 1 ;\ else\ - echo failed as expected; \ + echo "Test $$i failed as expected" ; \ fi ;\ done ;\ - echo; echo Bound test OK + echo Bound test OK # speed test speedtest: ex2 ex3 @@ -181,6 +220,7 @@ speedtest: ex2 ex3 time $(TCC) -run $(TOPSRC)/examples/ex3.c 35 weaktest: tcctest.c test.ref + @echo ------------ $@ ------------ $(TCC) -c $< -o weaktest.tcc.o $(CC) -c $< -o weaktest.gcc.o $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer objdump -t weaktest.tcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.tcc.o.txt @@ -206,22 +246,19 @@ asmtest2: MAYBE_RUN_TCC = $(RUN_TCC) # Check that code generated by libtcc is binary compatible with # that generated by CC -abitest-cc$(EXESUF): abitest.c $(LIBTCC) +abitest-cc.exe: abitest.c $(LIBTCC) $(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w -abitest-tcc$(EXESUF): abitest.c libtcc.c +abitest-tcc.exe: abitest.c libtcc.c $(TCC) -o $@ $^ $(NATIVE_DEFINES) $(LIBS) -ABITESTS := abitest-cc$(EXESUF) -ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float - ABITESTS += abitest-tcc$(EXESUF) -endif - -abitest: $(ABITESTS) +abitest-% : abitest-%.exe @echo ------------ $@ ------------ - ./abitest-cc$(EXESUF) $(TCCFLAGS) + ./$< $(TCCFLAGS) + +abitest: abitest-cc ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float - ./abitest-tcc$(EXESUF) $(TCCFLAGS) +abitest: abitest-tcc endif vla_test$(EXESUF): vla_test.c @@ -244,21 +281,18 @@ asm-c-connect-test: asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF) @echo ------------ $@ ------------ ./asm-c-connect$(EXESUF) > asm-c-connect.out1 && cat asm-c-connect.out1 ./asm-c-connect-sep$(EXESUF) > asm-c-connect.out2 && cat asm-c-connect.out2 - @diff -u asm-c-connect.out1 asm-c-connect.out2 && echo "ok" + @diff -u asm-c-connect.out1 asm-c-connect.out2 || (echo "error"; exit 1) + +TCC_YY = $(foreach T,$(TCC_X),$(if $(wildcard $(TOP)/$T-tcc$(EXESUF)),$T)) cross-test : + $(if $(strip $(TCC_YY)),\ + $(MAKE) $(foreach T,$(TCC_YY),cross-$T.test) --no-print-directory,:) + +cross-%.test : @echo ------------ $@ ------------ - $(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/x86_64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/arm64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok" - $(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok" - $(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok" - $(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/win32/examples/hello_win.c && echo "ok" + $(TOP)/$*-tcc$(EXESUF) -v $(TCCFLAGS-$(if $(findstring win,$*),win,unx))\ + -c $(TOPSRC)/examples/ex3.c # targets for development %.bin: %.c tcc @@ -279,11 +313,8 @@ cache: tcc_g clean: rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc rm -f *-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234] - rm -f asm-c-connect$(EXESUF) - rm -f ex? tcc_g weaktest.*.txt *.def + rm -f asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF) + rm -f ex? tcc_g weaktest.*.txt *.def *.pdb *.obj libtcc_test_mt @$(MAKE) -C tests2 $@ @$(MAKE) -C pp $@ -# silent clean, used before running tests -clean-s: - @$(MAKE) -s --no-print-directory clean diff --git a/tests/asm-c-connect-1.c b/tests/asm-c-connect-1.c index 8a28d78..d79270d 100644 --- a/tests/asm-c-connect-1.c +++ b/tests/asm-c-connect-1.c @@ -1,12 +1,19 @@ #include <stdio.h> -#if defined _WIN32 && !defined __TINYC__ +#if (defined _WIN32 || defined __APPLE__) && (!defined __TINYC__ || defined __leading_underscore) # define _ "_" #else # define _ #endif -static int x1_c(void) +#ifdef __clang__ +/* clang needs some help tp not throw functions away even at -O0 */ +#define __USED __attribute__((__used__)) +#else +#define __USED +#endif + +static int __USED x1_c (void) { printf(" x1"); return 1; @@ -37,7 +44,7 @@ int main(int argc, char *argv[]) } static -int x2(void) +int __USED x2(void) { printf(" x2"); return 2; diff --git a/tests/asm-c-connect-2.c b/tests/asm-c-connect-2.c index 3440b40..e2b4b59 100644 --- a/tests/asm-c-connect-2.c +++ b/tests/asm-c-connect-2.c @@ -1,11 +1,18 @@ #include <stdio.h> -#if defined _WIN32 && !defined __TINYC__ +#if (defined _WIN32 || defined __APPLE__) && (!defined __TINYC__ || defined __leading_underscore) # define _ "_" #else # define _ #endif +#ifdef __clang__ +/* clang needs some help tp not throw functions away even at -O0 */ +#define __USED __attribute__((__used__)) +#else +#define __USED +#endif + int x3(void) { printf(" x3"); @@ -30,7 +37,7 @@ void callx5_again(void) asm("call "_"x6"); } -static void x6() +static void __USED x6() { printf(" x6-2"); } diff --git a/tests/boundtest.c b/tests/boundtest.c index 15bffb4..0d83395 100644 --- a/tests/boundtest.c +++ b/tests/boundtest.c @@ -50,15 +50,12 @@ int test4(void) int i, sum = 0; int *tab4; - fprintf(stderr, "%s start\n", __FUNCTION__); - tab4 = malloc(20 * sizeof(int)); for(i=0;i<20;i++) { sum += tab4[i]; } free(tab4); - fprintf(stderr, "%s end\n", __FUNCTION__); return sum; } @@ -68,20 +65,16 @@ int test5(void) int i, sum = 0; int *tab4; - fprintf(stderr, "%s start\n", __FUNCTION__); - tab4 = malloc(20 * sizeof(int)); for(i=0;i<21;i++) { sum += tab4[i]; } free(tab4); - fprintf(stderr, "%s end\n", __FUNCTION__); return sum; } /* error */ -/* XXX: currently: bug */ int test6(void) { int i, sum = 0; @@ -176,21 +169,34 @@ int test13(void) return strlen(tab); } +#if defined __i386__ || defined __x86_64__ +#define allocf(x) +#else +#define alloca(x) malloc(x) +#define allocf(x) free(x) +#endif + int test14(void) { char *p = alloca(TAB_SIZE); + size_t ret; memset(p, 'a', TAB_SIZE); p[TAB_SIZE-1] = 0; - return strlen(p); + ret = strlen(p); + allocf(p); + return ret; } /* error */ int test15(void) { char *p = alloca(TAB_SIZE-1); + size_t ret; memset(p, 'a', TAB_SIZE); p[TAB_SIZE-1] = 0; - return strlen(p); + ret = strlen(p); + allocf(p); + return ret; } /* ok */ @@ -199,16 +205,14 @@ int test16() char *demo = "This is only a test."; char *p; - fprintf(stderr, "%s start\n", __FUNCTION__); - p = alloca(16); strcpy(p,"12345678901234"); - printf("alloca: p is %s\n", p); + allocf(p); /* Test alloca embedded in a larger expression */ - printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) ); + printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) ); - fprintf(stderr, "%s end\n", __FUNCTION__); + return 0; } /* error */ @@ -217,16 +221,24 @@ int test17() char *demo = "This is only a test."; char *p; - fprintf(stderr, "%s start\n", __FUNCTION__); - p = alloca(16); strcpy(p,"12345678901234"); - printf("alloca: p is %s\n", p); + allocf(p); /* Test alloca embedded in a larger expression */ - printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) ); + printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) ); + + return 0; +} - fprintf(stderr, "%s end\n", __FUNCTION__); +int test18(void) +{ + int i, sum = 0, n = TAB_SIZE; + int tab[n]; + for(i=0;i<TAB_SIZE+1;i++) { + sum += tab[i]; + } + return sum; } int (*table_test[])(void) = { @@ -247,14 +259,25 @@ int (*table_test[])(void) = { test15, test16, test17, + test18 }; int main(int argc, char **argv) { + int i; + char *cp; int index; int (*ftest)(void); int index_max = sizeof(table_test)/sizeof(table_test[0]); + /* check bounds checking main arg */ + for (i = 0; i < argc; i++) { + cp = argv[i]; + while (*cp) { + cp++; + } + } + if (argc < 2) { printf( "test TCC bound checking system\n" diff --git a/tests/bug.c b/tests/bug.c new file mode 100644 index 0000000..7ec4410 --- /dev/null +++ b/tests/bug.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdarg.h> + +void tst1(void) +{ + /* problem in gen_cast. Should mask unsigned types */ + signed char c = (signed char) 0xffffffff; + int r = (unsigned short) c ^ (signed char) 0x99999999; + if (r != 0xffff0066) printf ("%x\n", r); +} + +typedef struct{double x,y;}p; + +void tst2(int n,...) +{ + /* va_arg for struct double does not work on some targets */ + int i; + va_list args; + va_start(args,n); + for (i = 0; i < n; i++) { + p v = va_arg(args,p); + if (v.x != 1 || v.y != 2) printf("%g %g\n", v.x, v.y); + } + va_end(args); +} + +void tst3(void) +{ + /* Should VT_SYM be checked for TOK_builtin_constant_p */ + int r = __builtin_constant_p("c"); + if (r == 0) printf("%d\n",r); +} + +int compile_errors(void) +{ +#if TEST == 1 + { + /* Not constant */ + static int i = (&"Foobar"[1] - &"Foobar"[0]); + } +#endif +#if TEST == 2 + { + /* Not constant */ + struct{int c;}v; + static long i=((char*)&(v.c)-(char*)&v); + } +#endif +#if TEST == 3 + { + /* Not constant */ + static const short ar[] = { &&l1 - &&l1, &&l2 - &&l1 }; + void *p = &&l1 + ar[0]; + goto *p; + l1: return 1; + l2: return 2; + } +#endif +#if TEST == 4 + { + /* Only integer allowed */ + __builtin_return_address(0 + 1) != NULL; + } +#endif + return 0; +} + +int +main(void) +{ + p v = { 1, 2}; + tst1(); + tst2(1, v); + tst3(); +} diff --git a/tests/gcctestsuite.sh b/tests/gcctestsuite.sh index f3cc538..2be274c 100755..100644 --- a/tests/gcctestsuite.sh +++ b/tests/gcctestsuite.sh @@ -1,33 +1,48 @@ #!/bin/sh TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture -TCC="./tcc -B. -I. -DNO_TRAMPOLINES" -rm -f tcc.sum tcc.log +TCC="./tcc -B. -I. -DNO_TRAMPOLINES" +rm -f tcc.sum tcc.fail +nb_ok="0" nb_failed="0" +nb_exe_failed="0" for src in $TESTSUITE_PATH/compile/*.c ; do - echo $TCC -o /tmp/test.o -c $src - $TCC -o /tmp/test.o -c $src >> tcc.log 2>&1 + echo $TCC -o /tmp/tst.o -c $src + $TCC -o /tmp/tst.o -c $src >> tcc.fail 2>&1 if [ "$?" = "0" ] ; then - result="PASS" + result="PASS" + nb_ok=$(( $nb_ok + 1 )) else - result="FAIL" - nb_failed=$(( $nb_failed + 1 )) + result="FAIL" + nb_failed=$(( $nb_failed + 1 )) fi echo "$result: $src" >> tcc.sum done for src in $TESTSUITE_PATH/execute/*.c ; do - echo $TCC $src - $TCC $src >> tcc.log 2>&1 + echo $TCC $src -o /tmp/tst -lm + $TCC $src -o /tmp/tst -lm >> tcc.fail 2>&1 if [ "$?" = "0" ] ; then - result="PASS" + result="PASS" + if /tmp/tst >> tcc.fail 2>&1 + then + result="PASS" + nb_ok=$(( $nb_ok + 1 )) + else + result="FAILEXE" + nb_exe_failed=$(( $nb_exe_failed + 1 )) + fi else - result="FAIL" - nb_failed=$(( $nb_failed + 1 )) + result="FAIL" + nb_failed=$(( $nb_failed + 1 )) fi echo "$result: $src" >> tcc.sum done +echo "$nb_ok test(s) ok." >> tcc.sum +echo "$nb_ok test(s) ok." echo "$nb_failed test(s) failed." >> tcc.sum echo "$nb_failed test(s) failed." +echo "$nb_exe_failed test(s) exe failed." >> tcc.sum +echo "$nb_exe_failed test(s) exe failed." diff --git a/tests/libtcc_test.c b/tests/libtcc_test.c index 480d314..d21c7fe 100644 --- a/tests/libtcc_test.c +++ b/tests/libtcc_test.c @@ -6,9 +6,15 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <assert.h> #include "libtcc.h" +void handle_error(void *opaque, const char *msg) +{ + fprintf(opaque, "%s\n", msg); +} + /* this function is called by the generated code */ int add(int a, int b) { @@ -53,6 +59,14 @@ int main(int argc, char **argv) exit(1); } + assert(tcc_get_error_func(s) == NULL); + assert(tcc_get_error_opaque(s) == NULL); + + tcc_set_error_func(s, stderr, handle_error); + + assert(tcc_get_error_func(s) == handle_error); + assert(tcc_get_error_opaque(s) == stderr); + /* if tcclib.h and libtcc1.a are not installed, where can we find them */ for (i = 1; i < argc; ++i) { char *a = argv[i]; diff --git a/tests/libtcc_test_mt.c b/tests/libtcc_test_mt.c new file mode 100644 index 0000000..b17e8de --- /dev/null +++ b/tests/libtcc_test_mt.c @@ -0,0 +1,300 @@ +/* + * Multi-thread Test for libtcc + */ + +#ifndef FIB +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "libtcc.h" + +#define M 20 /* number of states */ +#define F(n) (n % 20 + 2) /* fib argument */ + +#ifdef _WIN32 +#include <windows.h> +#define TF_TYPE(func, param) DWORD WINAPI func(void *param) +typedef TF_TYPE(ThreadFunc, x); +HANDLE hh[M]; +void create_thread(ThreadFunc f, int n) +{ + DWORD tid; + hh[n] = CreateThread(NULL, 0, f, (void*)(size_t)n, 0, &tid); +} +void wait_threads(int n) +{ + WaitForMultipleObjects(n, hh, TRUE, INFINITE); + while (n) + CloseHandle(hh[--n]); +} +void sleep_ms(unsigned n) +{ + Sleep(n); +} +#else +#include <sys/time.h> +#include <unistd.h> +#include <pthread.h> +#define TF_TYPE(func, param) void* func(void *param) +typedef TF_TYPE(ThreadFunc, x); +pthread_t hh[M]; +void create_thread(ThreadFunc f, int n) +{ + pthread_create(&hh[n], NULL, f, (void*)(size_t)n); +} +void wait_threads(int n) +{ + while (n) + pthread_join(hh[--n], NULL); + +} +void sleep_ms(unsigned n) +{ + usleep(n * 1000); +} +#endif + +void handle_error(void *opaque, const char *msg) +{ + fprintf(opaque, "%s\n", msg); +} + +/* this function is called by the generated code */ +int add(int a, int b) +{ + return a + b; +} + +#define _str(s) #s +#define str(s) _str(s) +/* as a trick, prepend #line directive for better error/warning messages */ +#define PROG(lbl) \ + char lbl[] = "#line " str(__LINE__) " " str(__FILE__) "\n\n" + +PROG(my_program) +"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */ +"int add(int a, int b);\n" +"int fib(int n)\n" +"{\n" +" if (n <= 2)\n" +" return 1;\n" +" else\n" +" return add(fib(n-1),fib(n-2));\n" +"}\n" +"\n" +"int foo(int n)\n" +"{\n" +" printf(\" %d\", fib(n));\n" +" return 0;\n" +"# warning is this the correct file:line...\n" +"}\n"; + +int g_argc; char **g_argv; + +void parse_args(TCCState *s) +{ + int i; + /* if tcclib.h and libtcc1.a are not installed, where can we find them */ + for (i = 1; i < g_argc; ++i) { + char *a = g_argv[i]; + if (a[0] == '-') { + if (a[1] == 'B') + tcc_set_lib_path(s, a+2); + else if (a[1] == 'I') + tcc_add_include_path(s, a+2); + else if (a[1] == 'L') + tcc_add_library_path(s, a+2); + else if (a[1] == 'D') + tcc_define_symbol(s, a+2, NULL); + } + } +} + +TCCState *new_state(int w) +{ + TCCState *s = tcc_new(); + if (!s) { + fprintf(stderr, __FILE__ ": could not create tcc state\n"); + exit(1); + } + tcc_set_error_func(s, stdout, handle_error); + parse_args(s); + if (!w) tcc_set_options(s, "-w"); + tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + return s; +} + +void *reloc_state(TCCState *s, const char *entry) +{ + void *func; + tcc_add_symbol(s, "add", add); + if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) { + fprintf(stderr, __FILE__ ": could not relocate tcc state.\n"); + return NULL; + } + func = tcc_get_symbol(s, entry); + if (!func) + fprintf(stderr, __FILE__ ": could not get entry symbol.\n"); + return func; +} + +/* work with several states at the same time */ +int state_test(void) +{ + TCCState *s[M]; + int (*func[M])(int); + int n; + + for (n = 0; n < M + 4; ++n) { + unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4; + if (a < M) + s[a] = new_state(0); + if (b < M) + if (tcc_compile_string(s[b], my_program) == -1) + break; + if (c < M) + func[c] = reloc_state(s[c], "foo"); + if (d < M && func[d]) + func[d](F(d)); + if (e < M) + tcc_delete(s[e]); + } + return 0; +} + +/* simple compilation in threads */ +TF_TYPE(thread_test_simple, vn) +{ + TCCState *s; + int (*func)(int); + int ret; + int n = (size_t)vn; + + s = new_state(0); + sleep_ms(1); + ret = tcc_compile_string(s, my_program); + sleep_ms(1); + if (ret >= 0) { + func = reloc_state(s, "foo"); + if (func) + func(F(n)); + } + tcc_delete(s); + return 0; +} + +/* more complex compilation in threads */ +TF_TYPE(thread_test_complex, vn) +{ + TCCState *s; + int ret; + int n = (size_t)vn; + char *argv[30], b[10]; + int argc = 0, i; + + sprintf(b, "%d", F(n)); + + for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i]; +#if 0 + argv[argc++] = "-run"; + for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i]; +#endif + argv[argc++] = "-DFIB"; + argv[argc++] = "-run"; + argv[argc++] = __FILE__; + argv[argc++] = b; + argv[argc] = NULL; + + s = new_state(1); + sleep_ms(2); + ret = tcc_add_file(s, argv[0]); + sleep_ms(3); + if (ret < 0) + exit(1); + tcc_run(s, argc, argv); + tcc_delete(s); + fflush(stdout); + return 0; +} + +void time_tcc(int n, const char *src) +{ + TCCState *s; + int ret; + while (--n >= 0) { + s = new_state(1); + ret = tcc_add_file(s, src); + tcc_delete(s); + if (ret < 0) + exit(1); + } +} + +static unsigned getclock_ms(void) +{ +#ifdef _WIN32 + return GetTickCount(); +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000 + (tv.tv_usec+500)/1000; +#endif +} + +int main(int argc, char **argv) +{ + int n; + unsigned t; + + g_argc = argc; + g_argv = argv; + + if (argc < 2) { + fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n"); + return 1; + } + +#if 1 + printf("running fib with mixed calls\n "), fflush(stdout); + t = getclock_ms(); + state_test(); + printf("\n (%u ms)\n", getclock_ms() - t); +#endif +#if 1 + printf("running fib in threads\n "), fflush(stdout); + t = getclock_ms(); + for (n = 0; n < M; ++n) + create_thread(thread_test_simple, n); + wait_threads(n); + printf("\n (%u ms)\n", getclock_ms() - t); +#endif +#if 1 + printf("running tcc.c in threads to run fib\n"), fflush(stdout); + t = getclock_ms(); + for (n = 0; n < M; ++n) + create_thread(thread_test_complex, n); + wait_threads(n); + printf("\n (%u ms)\n", getclock_ms() - t); +#endif +#if 1 + printf("compiling tcc.c 10 times\n"), fflush(stdout); + t = getclock_ms(); + time_tcc(10, argv[1]); + printf(" (%u ms)\n", getclock_ms() - t), fflush(stdout); +#endif + return 0; +} + +#else +#include <tcclib.h> +int fib(n) +{ + return (n <= 2) ? 1 : fib(n-1) + fib(n-2); +} + +int main(int argc, char **argv) +{ + printf(" %d", fib(atoi(argv[1]), 2)); + return 0; +} +#endif diff --git a/tests/misc/c2str.c b/tests/misc/c2str.c new file mode 100644 index 0000000..01d18db --- /dev/null +++ b/tests/misc/c2str.c @@ -0,0 +1,112 @@ +#include <stdio.h> +#include <string.h> + +int isid(int c) +{ + return (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c == '_'; +} + +int isspc(int c) +{ + return c == ' ' || c == '\t'; +} + +int main(int argc, char **argv) +{ + char l[1000], *p, l2[1000], *q; + FILE *fp, *op; + int c, e, f; + + if (argc < 3) + return 1; + + fp = fopen(argv[1], "rb"); + op = fopen(argv[2], "wb"); + if (!fp || !op) { + fprintf(stderr, "c2str: file error\n"); + return 1; + } + + for (;;) { + p = l; + append: + if (fgets(p, sizeof l - (p - l), fp)) { + p = strchr(p, 0); + while (p > l && p[-1] == '\n') + --p; + *p = 0; + } else if (p == l) + break; + if (p > l && p[-1] == '\\') { + --p; + goto append; + } + + if (l[0] == 0) + continue; + p = l, q = l2, f = e = 0; + while (*p && isspc(*p)) + ++p, ++f; + + if (f < 4) { + do { + static const char *sr[] = { + "__x86_64__", "TCC_TARGET_X86_64", + "_WIN64", "TCC_TARGET_PE", + "_WIN32", "TCC_TARGET_PE", + "__arm__", "TCC_TARGET_ARM", + "__aarch64__", "TCC_TARGET_ARM64", + "__riscv", "TCC_TARGET_RISCV64", + "__i386__", "TCC_TARGET_I386", 0 }; + for (f = 0; sr[f]; f += 2) { + c = strlen(sr[f]); + if (0 == memcmp(p, sr[f], c)) { + p += c, ++f; + q = strchr(strcpy(q, sr[f]), 0); + break; + } + + } + if (sr[f]) + continue; + } while (!!(*q++ = *p++)); + + fprintf(op, "%s\n", l2); + + } else if (*p == '/') { + strcpy(q, p); + fprintf(op, " %s\n", l2); + + } else { + f = 0; + for (;;) { + c = *p++; + if (isspc(c)) { + if (q == l2 || isspc(q[-1])) + continue; + if ((f > 2 || e) || (q[-1] != ')' && *p != '(')) { + if (!isid(q[-1]) || !isid(*p)) + continue; + } + } + if (c == '(') + ++e, ++f; + if (c == ')') + --e, ++f; + if (c == '\\' || c == '\"') + *q++ = '\\'; + *q++ = c; + if (c == 0) + break; + } + fprintf(op, " \"%s\\n\"\n", l2); + } + } + + fclose(fp); + fclose(op); + return 0; +} diff --git a/tests/misc/tcc_predefs.h b/tests/misc/tcc_predefs.h new file mode 100644 index 0000000..bbba425 --- /dev/null +++ b/tests/misc/tcc_predefs.h @@ -0,0 +1,111 @@ +#if defined __x86_64__ +#ifndef _WIN64 + /* GCC compatible definition of va_list. */ + /* This should be in sync with the declaration in our lib/libtcc1.c */ + typedef struct { + unsigned gp_offset, fp_offset; + union { + unsigned overflow_offset; + char *overflow_arg_area; + }; + char *reg_save_area; + } __builtin_va_list[1]; + + void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); + #define __builtin_va_start(ap, last) \ + (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) + #define __builtin_va_arg(ap, t) \ + (*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t)))) + #define __builtin_va_copy(dest, src) (*(dest) = *(src)) + +#else /* _WIN64 */ + typedef char *__builtin_va_list; + #define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ + ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) +#endif + +#elif defined __arm__ + typedef char *__builtin_va_list; + #define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x) + #define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \ + & ~(_tcc_alignof(type) - 1)) + #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) + #define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ + &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) + +#elif defined __aarch64__ + typedef struct { + void *__stack, *__gr_top, *__vr_top; + int __gr_offs, __vr_offs; + } __builtin_va_list; + +#elif defined __riscv + typedef char *__builtin_va_list; + #define __va_reg_size (__riscv_xlen >> 3) + #define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \ + & -(__alignof__(type))) + #define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size))))) + +#else /* __i386__ */ + typedef char *__builtin_va_list; + #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) + #define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3))) + +#endif + #define __builtin_va_end(ap) (void)(ap) + #ifndef __builtin_va_copy + # define __builtin_va_copy(dest, src) (dest) = (src) + #endif + + + /* TCC BBUILTIN AND BOUNDS ALIASES */ + #ifdef __BOUNDS_CHECKING_ON + # define __BUILTIN(ret,name,params) \ + ret __builtin_##name params __attribute__((alias("__bound_" #name))); + # define __BOUND(ret,name,params) \ + ret name params __attribute__((alias("__bound_" #name))); + #else + # define __BUILTIN(ret,name,params) \ + ret __builtin_##name params __attribute__((alias(#name))); + # define __BOUND(ret,name,params) + #endif + # define __BOTH(ret,name,params) \ + __BUILTIN(ret,name,params) __BOUND(ret,name,params) + + __BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__)) + __BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__)) + __BOTH(void*, memset, (void *, int, __SIZE_TYPE__)) + __BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__)) + __BOTH(__SIZE_TYPE__, strlen, (const char *)) + __BOTH(char*, strcpy, (char *, const char *)) + __BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__)) + __BOTH(int, strcmp, (const char*, const char*)) + __BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__)) + __BOTH(char*, strcat, (char*, const char*)) + __BOTH(char*, strchr, (const char*, int)) + __BOTH(char*, strdup, (const char*)) + +#ifdef _WIN32 + #define __MAYBE_REDIR __BOTH +#else // HAVE MALLOC_REDIR + #define __MAYBE_REDIR __BUILTIN +#endif + __MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__)) + __MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__)) + __MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__)) + __MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__)) + __MAYBE_REDIR(void, free, (void*)) + +#if defined __i386__ || defined __x86_64__ + __BOTH(void*, alloca, (__SIZE_TYPE__)) +#endif + __BUILTIN(void, abort, (void)) + __BOUND(int, longjmp, ()) +#ifndef _WIN32 + __BOUND(void*, mmap, ()) + __BOUND(void*, munmap, ()) +#endif + #undef __BUILTIN + #undef __BOUND + #undef __BOTH + #undef __MAYBE_REDIR diff --git a/tests/pp/Makefile b/tests/pp/Makefile index 687aa52..4785db3 100644 --- a/tests/pp/Makefile +++ b/tests/pp/Makefile @@ -10,7 +10,7 @@ VPATH = $(SRC) files = $(patsubst %.$1,%.test,$(notdir $(wildcard $(SRC)/*.$1))) TESTS = $(call files,c) $(call files,S) -all test : $(sort $(TESTS)) +all test testspp.all: $(sort $(TESTS)) DIFF_OPTS = -Nu -b -B @@ -29,6 +29,8 @@ FILTER = 2>&1 | sed 's,$(SRC)/,,g' diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \ && rm -f $*.output +testspp.%: %.test ; + # automatically generate .expect files with gcc: %.expect: # %.c gcc -E -P $*.[cS] >$*.expect 2>&1 diff --git a/tests/tcctest.c b/tests/tcctest.c index 57670be..4ac2cc0 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3,7 +3,10 @@ */ #include "config.h" -#if GCC_MAJOR >= 3 +/* identify the configured reference compiler in use */ +#define CC_gcc 1 +#define CC_clang 2 +#define CC_tcc 3 /* Unfortunately, gcc version < 3 does not handle that! */ #define ALL_ISOC99 @@ -11,9 +14,11 @@ /* only gcc 3 handles _Bool correctly */ #define BOOL_ISOC99 -/* gcc 2.95.3 does not handle correctly CR in strings or after strays */ -#define CORRECT_CR_HANDLING +/* __VA_ARGS__ and __func__ support */ +#define C99_MACROS +#ifndef __TINYC__ +typedef __SIZE_TYPE__ uintptr_t; #endif #if defined(_WIN32) @@ -33,12 +38,6 @@ #define LONG_DOUBLE_LITERAL(x) x ## L #endif -/* deprecated and no longer supported in gcc 3.3 */ -//#define ACCEPT_CR_IN_STRINGS - -/* __VA_ARGS__ and __func__ support */ -#define C99_MACROS - /* test various include syntaxes */ #define TCCLIB_INC <tcclib.h> @@ -64,65 +63,19 @@ #define INC(name) <tests/name.h> #define funnyname 42test.h #define incdir tests/ +#ifdef __clang__ +/* clang's preprocessor is broken in this regard and adds spaces + to the tokens 'incdir' and 'funnyname' when expanding */ +#define incname <tests/42test.h> +#else #define incname < incdir funnyname > +#endif #define __stringify(x) #x #define stringify(x) __stringify(x) #include INC(42test) #include incname #include stringify(funnyname) -void intdiv_test(); -void string_test(); -void expr_test(); -void macro_test(); -void recursive_macro_test(); -void scope_test(); -void forward_test(); -void funcptr_test(); -void loop_test(); -void switch_test(); -void goto_test(); -void enum_test(); -void typedef_test(); -void struct_test(); -void array_test(); -void expr_ptr_test(); -void bool_test(); -void optimize_out(); -void expr2_test(); -void constant_expr_test(); -void expr_cmp_test(); -void char_short_test(); -void init_test(void); -void compound_literal_test(void); -int kr_test(); -void struct_assign_test(void); -void cast_test(void); -void bitfield_test(void); -void c99_bool_test(void); -void float_test(void); -void longlong_test(void); -void manyarg_test(void); -void stdarg_test(void); -void whitespace_test(void); -void relocation_test(void); -void old_style_function(void); -void alloca_test(void); -void c99_vla_test(int size1, int size2); -void sizeof_test(void); -void typeof_test(void); -void local_label_test(void); -void statement_expr_test(void); -void asm_test(void); -void builtin_test(void); -void weak_test(void); -void global_data_test(void); -void cmp_comparison_test(void); -void math_cmp_test(void); -void callsave_test(void); -void builtin_frame_address_test(void); -void attrib_test(void); - int fib(int n); void num(int n); void forward_ref(void); @@ -133,8 +86,6 @@ int isid(int c); void funny_line_continuation (int, ..\ . ); -char via_volatile (char); - #define A 2 #define N 1234 + A #define pf printf @@ -178,7 +129,7 @@ static int onetwothree = 123; #ifdef __TINYC__ /* We try to handle this syntax. Make at least sure it doesn't segfault. */ -char invalid_function_def()[] {} +char invalid_function_def()[] {return 0;} #endif #define __INT64_C(c) c ## LL @@ -194,74 +145,8 @@ int qq(int x) #define wq_spin_lock spin_lock #define TEST2() wq_spin_lock(a) -#define UINT_MAX ((unsigned) -1) - -void intdiv_test(void) -{ - printf("18/21=%u\n", 18/21); - printf("18%%21=%u\n", 18%21); - printf("41/21=%u\n", 41/21); - printf("41%%21=%u\n", 41%21); - printf("42/21=%u\n", 42/21); - printf("42%%21=%u\n", 42%21); - printf("43/21=%u\n", 43/21); - printf("43%%21=%u\n", 43%21); - printf("126/21=%u\n", 126/21); - printf("126%%21=%u\n", 126%21); - printf("131/21=%u\n", 131/21); - printf("131%%21=%u\n", 131%21); - printf("(UINT_MAX/2+3)/2=%u\n", (UINT_MAX/2+3)/2); - printf("(UINT_MAX/2+3)%%2=%u\n", (UINT_MAX/2+3)%2); - - printf("18/-21=%u\n", 18/-21); - printf("18%%-21=%u\n", 18%-21); - printf("41/-21=%u\n", 41/-21); - printf("41%%-21=%u\n", 41%-21); - printf("42/-21=%u\n", 42/-21); - printf("42%%-21=%u\n", 42%-21); - printf("43/-21=%u\n", 43/-21); - printf("43%%-21=%u\n", 43%-21); - printf("126/-21=%u\n", 126/-21); - printf("126%%-21=%u\n", 126%-21); - printf("131/-21=%u\n", 131/-21); - printf("131%%-21=%u\n", 131%-21); - printf("(UINT_MAX/2+3)/-2=%u\n", (UINT_MAX/2+3)/-2); - printf("(UINT_MAX/2+3)%%-2=%u\n", (UINT_MAX/2+3)%-2); - - printf("-18/21=%u\n", -18/21); - printf("-18%%21=%u\n", -18%21); - printf("-41/21=%u\n", -41/21); - printf("-41%%21=%u\n", -41%21); - printf("-42/21=%u\n", -42/21); - printf("-42%%21=%u\n", -42%21); - printf("-43/21=%u\n", -43/21); - printf("-43%%21=%u\n", -43%21); - printf("-126/21=%u\n", -126/21); - printf("-126%%21=%u\n", -126%21); - printf("-131/21=%u\n", -131/21); - printf("-131%%21=%u\n", -131%21); - printf("-(UINT_MAX/2+3)/2=%u\n", (0-(UINT_MAX/2+3))/2); - printf("-(UINT_MAX/2+3)%%2=%u\n", (0-(UINT_MAX/2+3))%2); - - printf("-18/-21=%u\n", -18/-21); - printf("-18%%-21=%u\n", -18%-21); - printf("-41/-21=%u\n", -41/-21); - printf("-41%%-21=%u\n", -41%-21); - printf("-42/-21=%u\n", -42/-21); - printf("-42%%-21=%u\n", -42%-21); - printf("-43/-21=%u\n", -43/-21); - printf("-43%%-21=%u\n", -43%-21); - printf("-126/-21=%u\n", -126/-21); - printf("-126%%-21=%u\n", -126%-21); - printf("-131/-21=%u\n", -131/-21); - printf("-131%%-21=%u\n", -131%-21); - printf("-(UINT_MAX/2+3)/-2=%u\n", (0-(UINT_MAX/2+3))/-2); - printf("-(UINT_MAX/2+3)%%-2=%u\n", (0-(UINT_MAX/2+3))%-2); -} - void macro_test(void) { - printf("macro:\n");
pf("N=%d\n", N); printf("aaa=%d\n", AAA); @@ -336,22 +221,6 @@ void macro_test(void) MACRO_NOARGS(); -#ifdef __LINE__ - printf("__LINE__ defined\n"); -#endif - - printf("__LINE__=%d __FILE__=%s\n", - __LINE__, __FILE__); -#if 0 -#line 200 - printf("__LINE__=%d __FILE__=%s\n", - __LINE__, __FILE__); -#line 203 "test" - printf("__LINE__=%d __FILE__=%s\n", - __LINE__, __FILE__); -#line 227 "tcctest.c" -#endif - /* not strictly preprocessor, but we test it there */ #ifdef C99_MACROS printf("__func__ = %s\n", __func__); @@ -408,15 +277,25 @@ comment comment. */ TEST2 /* the comment */ (); - printf("%s\n", get_basefile_from_header()); - printf("%s\n", __BASE_FILE__); - printf("%s\n", get_file_from_header()); - printf("%s\n", __FILE__); + printf("basefromheader %s\n", get_basefile_from_header()); + printf("base %s\n", __BASE_FILE__); + { + /* Some compilers (clang) prepend './' to __FILE__ from included + files. */ + const char *fn = get_file_from_header(); + if (fn[0] == '.' && fn[1] == '/') + fn += 2; + printf("filefromheader %s\n", fn); + } + printf("file %s\n", __FILE__); /* Check that funnily named include was in fact included */ have_included_42test_h = 1; have_included_42test_h_second = 1; have_included_42test_h_third = 1; + + /* Check that we don't complain about stray \ here */ + printf("print a backslash: %s\n", stringify(\\)); } @@ -461,6 +340,56 @@ int ret(a) return 0; } +#if !defined(__TINYC__) && (__GNUC__ >= 8) +/* Old GCCs don't regard "foo"[1] as constant, even in GNU dialect. */ +#define CONSTANTINDEXEDSTRLIT +#endif +char str_ag1[] = "b"; +char str_ag2[] = { "b" }; +/*char str_bg1[] = ("cccc"); GCC accepts this with pedantic warning, TCC not */ +#ifdef CONSTANTINDEXEDSTRLIT +char str_ag3[] = { "ab"[1], 0 }; +char str_x[2] = { "xy" "z"[2], 0 }; +#endif +char *str_ar[] = { "one", "two" }; +struct str_SS {unsigned char a[3], b; }; +struct str_SS str_sinit15 = { "r" }; +struct str_SS str_sinit16[] = { { "q" }, 2 }; + +static void string_test2() +{ + char *p = "hello"; + char a3[2] = { "p" }; + char a4[2] = { "ab" "c"[2], 0 }; + char *pa1 = "def" + 1; + char *pa2 = { "xyz" + 1 }; + int i = 0; + struct str_SS ss = { { [0 ... 1] = 'a' }, 0 }; +#ifndef CONSTANTINDEXEDSTRLIT + char str_ag3[] = { "ab"[1], 0 }; + char str_x[2] = { "xy" "z"[2], 0 }; +#endif + puts("string_test2"); + puts(str_ag1); + puts(str_ag2); + /*puts(str_bg1);*/ + puts(str_ag3); + puts(str_x); + puts(str_sinit15.a); + puts(str_sinit16[0].a); + puts(a3); + puts(a4); + puts(p); + puts("world"); + printf("%s\n", "bla"); + puts(str_ar[0]); + puts(str_ar[1]); + puts(ss.a); + puts(i >= 0 ? "one" : "two"); + puts(pa1); + puts(pa2); +} + void ps(const char *s) { int c; @@ -505,6 +434,52 @@ void string_test() num(b); b = b * 2; } + string_test2(); +} + + +void if1t(int n, int a, int b, int c) +{ + if (a && b) printf("if1t: %d 1 %d %d\n", n, a, b); + if (a && !b) printf("if1t: %d 2 %d %d\n", n, a, b); + if (!a && b) printf("if1t: %d 3 %d %d\n", n, a, b); + if (!a && !b) printf("if1t: %d 4 %d %d\n", n, a, b); + if (a || b) printf("if1t: %d 5 %d %d\n", n, a, b); + if (a || !b) printf("if1t: %d 6 %d %d\n", n, a, b); + if (!a || b) printf("if1t: %d 7 %d %d\n", n, a, b); + if (!a || !b) printf("if1t: %d 8 %d %d\n", n, a, b); + if (a && b || c) printf("if1t: %d 9 %d %d %d\n", n, a, b, c); + if (a || b && c) printf("if1t: %d 10 %d %d %d\n", n, a, b, c); + if (a > b - 1 && c) printf("if1t: %d 11 %d %d %d\n", n, a, b, c); + if (a > b - 1 || c) printf("if1t: %d 12 %d %d %d\n", n, a, b, c); + if (a > 0 && 1) printf("if1t: %d 13 %d %d %d\n", n, a, b, c); + if (a > 0 || 0) printf("if1t: %d 14 %d %d %d\n", n, a, b, c); +} + +void if2t(void) +{ + if (0 && 1 || printf("if2t:ok\n") || 1) + printf("if2t:ok2\n"); + printf("if2t:ok3\n"); +} + +void if3t(void) +{ + volatile long long i = 1; + if (i <= 18446744073709551615ULL) + ; + else + printf ("if3t:wrong 1\n"); +} + +void if_test(void) +{ + if1t(1, 0, 0, 0); + if1t(2, 0, 3, 0); + if1t(3, 2, 0, 0); + if1t(4, 2, 3, 0); + if2t(); + if3t(); } void loop_test() @@ -568,9 +543,10 @@ void goto_test() int i; static void *label_table[3] = { &&label1, &&label2, &&label3 }; - printf("goto:\n"); + printf("\ngoto:\n"); i = 0; /* This needs to parse as label, not as start of decl. */ + typedef_and_label x; typedef_and_label: s_loop: if (i >= 10) @@ -635,8 +611,7 @@ void enum_test() /* The following should give no warning */ unsigned *p = &b1; struct S_enum s = {E7}; - printf("enum: %d\n", s.e); - printf("enum:\n%d %d %d %d %d %d\n", + printf("%d %d %d %d %d %d %d\n", s.e, E0, E1, E2, E3, E4, E5); b1 = 1; printf("b1=%d\n", b1); @@ -665,7 +640,6 @@ void typedef_test() a = &b; *a = 1234; - printf("typedef:\n"); printf("a=%d\n", *a); mytype2 = 2; printf("mytype2=%d\n", mytype2); @@ -673,7 +647,6 @@ void typedef_test() void forward_test() { - printf("forward:\n"); forward_ref(); forward_ref(); } @@ -711,66 +684,6 @@ struct empty_mem { int x; }; -int main(int argc, char **argv) -{ - string_test(); - expr_test(); - macro_test(); - recursive_macro_test(); - scope_test(); - forward_test(); - funcptr_test(); - loop_test(); - switch_test(); - goto_test(); - enum_test(); - typedef_test(); - struct_test(); - array_test(); - expr_ptr_test(); - bool_test(); - optimize_out(); - expr2_test(); - constant_expr_test(); - expr_cmp_test(); - char_short_test(); - init_test(); - compound_literal_test(); - kr_test(); - struct_assign_test(); - cast_test(); - bitfield_test(); - c99_bool_test(); - float_test(); - longlong_test(); - manyarg_test(); - stdarg_test(); - whitespace_test(); - relocation_test(); - old_style_function(); - alloca_test(); - c99_vla_test(5, 2); - sizeof_test(); - typeof_test(); - statement_expr_test(); - local_label_test(); - asm_test(); - builtin_test(); -#ifndef _WIN32 - weak_test(); -#endif - global_data_test(); - cmp_comparison_test(); - math_cmp_test(); - callsave_test(); - builtin_frame_address_test(); - intdiv_test(); - if (via_volatile (42) != 42) - printf ("via_volatile broken\n"); - attrib_test(); - return 0; -} - int tab[3]; int tab2[3][2]; @@ -783,7 +696,6 @@ void f1(g) void scope_test() { - printf("scope:\n"); g = 2; f1(1); printf("g2=%d\n", g); @@ -800,11 +712,34 @@ void scope_test() printf("g5=%d\n", g); } +int st2_i; +int *st2_p = &st2_i; +void scope2_test() +{ + char a[50]; + st2_i = 42; + for (int st2_i = 1; st2_i < 10; st2_i++) { + extern int st2_i; + st2_i++; + printf("exloc: %d\n", st2_i); + } + printf("exloc: %d\n", *st2_p); +} + +/* C has tentative definition, and they may be repeated. */ +extern int st_global1; +int st_global1=42; +extern int st_global1; +int st_global1; +extern int st_global2; +int st_global2; +extern int st_global2; +int st_global2; + void array_test() { int i, j, a[4]; - printf("array:\n"); printf("sizeof(a) = %d\n", sizeof(a)); printf("sizeof(\"a\") = %d\n", sizeof("a")); #ifdef C99_MACROS @@ -909,7 +844,6 @@ void expr2_test() { int a, b; - printf("expr2:\n"); vstack_ptr = vstack; vpush(1432432, 2); vstack_ptr[-2] &= ~0xffffff80; @@ -917,14 +851,16 @@ void expr2_test() printf("res= %d %d\n", a, b); } +int const_len_ar[sizeof(1/0)]; /* div-by-zero, but in unevaluated context */ + void constant_expr_test() { int a; - printf("constant_expr:\n"); a = 3; printf("%d\n", a * 16); printf("%d\n", a * 1); printf("%d\n", a + 0); + printf("%d\n", sizeof(const_len_ar)); } int tab4[10]; @@ -934,7 +870,6 @@ void expr_ptr_test() int *p, *q; int i = -1; - printf("expr_ptr:\n"); p = tab4; q = tab4 + 10; printf("diff=%d\n", q - p); @@ -990,7 +925,6 @@ void expr_ptr_test() void expr_cmp_test() { int a, b; - printf("constant_expr:\n"); a = -1; b = 1; printf("%d\n", a == a); @@ -1110,7 +1044,6 @@ void struct_test() union union2 u; struct Large ls; - printf("struct:\n"); printf("sizes: %d %d %d %d\n", sizeof(struct struct1), sizeof(struct struct2), @@ -1134,7 +1067,7 @@ void struct_test() s->f3 = 1; printf("st2: %d %d %d\n", s->f1, s->f2, s->f3); - printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1); + printf("str_addr=%x\n", (int)(uintptr_t)st1.str - (int)(uintptr_t)&st1.f1); /* align / size tests */ printf("aligntest1 sizeof=%d alignof=%d\n", @@ -1174,17 +1107,22 @@ void struct_test() printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls)); } +/* simulate char/short return value with undefined upper bits */ +static int __csf(int x) { return x; } +static void *_csf = __csf; +#define csf(t,n) ((t(*)(int))_csf)(n) + /* XXX: depend on endianness */ void char_short_test() { int var1, var2; - - printf("char_short:\n"); + signed char var3; + long long var4; var1 = 0x01020304; var2 = 0xfffefdfc; printf("s8=%d %d\n", - *(char *)&var1, *(char *)&var2); + *(signed char *)&var1, *(signed char *)&var2); printf("u8=%d %d\n", *(unsigned char *)&var1, *(unsigned char *)&var2); printf("s16=%d %d\n", @@ -1195,12 +1133,44 @@ void char_short_test() *(int *)&var1, *(int *)&var2); printf("u32=%d %d\n", *(unsigned int *)&var1, *(unsigned int *)&var2); - *(char *)&var1 = 0x08; + *(signed char *)&var1 = 0x08; printf("var1=%x\n", var1); *(short *)&var1 = 0x0809; printf("var1=%x\n", var1); *(int *)&var1 = 0x08090a0b; printf("var1=%x\n", var1); + + var1 = 0x778899aa; + var4 = 0x11223344aa998877ULL; + var1 = var3 = var1 + 1; + var4 = var3 = var4 + 1; + printf("promote char/short assign %d "LONG_LONG_FORMAT"\n", var1, var4); + var1 = 0x778899aa; + var4 = 0x11223344aa998877ULL; + printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1); + printf("promote char/short cast VA %d %d\n", (signed char)(var1 + 1), (signed char)(var4 + 1)); +#if !defined(__arm__) + /* We can't really express GCC behaviour of return type promotion in + the presence of undefined behaviour (like __csf is). */ + var1 = csf(unsigned char,0x89898989); + var4 = csf(signed char,0xabababab); + printf("promote char/short funcret %d "LONG_LONG_FORMAT"\n", var1, var4); + printf("promote char/short fumcret VA %d %d %d %d\n", + csf(unsigned short,0xcdcdcdcd), + csf(short,0xefefefef), + csf(_Bool,0x33221100), + csf(_Bool,0x33221101)); +#endif + var3 = -10; + var1 = (signed char)(unsigned char)(var3 + 1); + var4 = (signed char)(unsigned char)(var3 + 1); + printf("promote multicast (char)(unsigned char) %d "LONG_LONG_FORMAT"\n", var1, var4); + var4 = 0x11223344aa998877ULL; + var4 = (unsigned)(int)(var4 + 1); + printf("promote multicast (unsigned)(int) "LONG_LONG_FORMAT"\n", var4); + var4 = 0x11223344bbaa9988ULL; + var4 = (unsigned)(signed char)(var4 + 1); + printf("promote multicast (unsigned)(char) "LONG_LONG_FORMAT"\n", var4); } /******************/ @@ -1307,12 +1277,16 @@ void bool_test() extern int undefined_function(void); extern int defined_function(void); +#ifdef __clang__ +int undefined_function(void) {} +#endif + static inline void refer_to_undefined(void) { undefined_function(); } -void optimize_out(void) +void optimize_out_test(void) { int i = 0 ? undefined_function() : defined_function(); printf ("oo:%d\n", i); @@ -1374,6 +1348,12 @@ void optimize_out(void) printf("ool6:%d\n", defined_function()); goto breakhere; } + j = 1; + while (j) { + j--; + continue; + printf("ool7:%d\n", undefined_function()); + } /* Test that constants in logical && are optimized: */ i = 0 && undefined_function(); @@ -1433,6 +1413,9 @@ int defined_function(void) static int tab_reinit[]; static int tab_reinit[10]; +static int tentative_ar[]; +static int tentative_ar[] = {1,2,3}; + //int cinit1; /* a global variable can be defined several times without error ! */ int cinit1; int cinit1; @@ -1444,8 +1427,6 @@ void compound_literal_test(void) int *p, i; char *q, *q3; - printf("compound_test:\n"); - p = (int []){1, 2, 3}; for(i=0;i<3;i++) printf(" %d", p[i]); @@ -1497,7 +1478,6 @@ int kr_func2(a, b) kr_test() { - printf("kr_test:\n"); printf("func1=%d\n", kr_func1(3, 4)); printf("func2=%d\n", kr_func2(3, 4)); return 0; @@ -1553,8 +1533,6 @@ void struct_assign_test(void) ps = &s; ps->i = 4; #if 0 - printf("struct_assign_test:\n"); - s.lsta1.f1 = 1; s.lsta1.f2 = 2; printf("%d %d\n", s.lsta1.f1, s.lsta1.f2); @@ -1597,9 +1575,9 @@ void cast_test() unsigned b,d; short s; char *p = NULL; + unsigned long ul = 0x80000000UL; p -= 0x700000000042; - printf("cast_test:\n"); a = 0xfffff; cast1(a, a, a, a); a = 0xffffe; @@ -1640,15 +1618,20 @@ void cast_test() printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a')); printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a')); +#if CC_NAME != CC_clang /* clang doesn't support non-portable conversions */ /* from pointer to integer types */ printf("%d %d %ld %ld %lld %lld\n", (int)p, (unsigned int)p, (long)p, (unsigned long)p, (long long)p, (unsigned long long)p); +#endif /* from integers to pointers */ printf("%p %p %p %p\n", (void *)a, (void *)b, (void *)c, (void *)d); + + /* int to int with sign set */ + printf("0x%lx\n", (unsigned long)(int)ul); } /* initializers tests */ @@ -1752,6 +1735,8 @@ arrtype2 sinit22 = {5,6,7}; int sinit23[2] = { "astring" ? sizeof("astring") : -1, &sinit23 ? 42 : -1 }; +int sinit24 = 2 || 1 / 0; /* exception in constant but unevaluated context */ + extern int external_inited = 42; void init_test(void) @@ -1772,8 +1757,6 @@ void init_test(void) /* Addresses on non-weak symbols are non-zero, but not the access itself */ int linit18[2] = {&zero ? 1 : -1, zero ? -1 : 1 }; - printf("init_test:\n"); - printf("sinit1=%d\n", sinit1); printf("sinit2=%d\n", sinit2); printf("sinit3=%d %d %d %d\n", @@ -1866,6 +1849,7 @@ void init_test(void) printf("arrtype6: %d\n", sizeof(arrtype2)); printf("sinit23= %d %d\n", sinit23[0], sinit23[1]); + printf("sinit24=%d\n", sinit24); printf("linit18= %d %d\n", linit18[0], linit18[1]); } @@ -1991,9 +1975,8 @@ void c99_bool_test(void) { #ifdef BOOL_ISOC99 int a; - _Bool b; + _Bool b, b2; - printf("bool_test:\n"); printf("sizeof(_Bool) = %d\n", sizeof(_Bool)); a = 3; printf("cast: %d %d %d\n", (_Bool)10, (_Bool)0, (_Bool)a); @@ -2001,6 +1984,9 @@ void c99_bool_test(void) printf("b = %d\n", b); b++; printf("b = %d\n", b); + b2 = 0; + printf("sizeof(x ? _Bool : _Bool) = %d (should be sizeof int)\n", + sizeof((volatile)a ? b : b2)); #endif } @@ -2018,7 +2004,6 @@ void bitfield_test(void) int f4 : 7; unsigned int f5 : 7; } st1; - printf("bitfield_test:"); printf("sizeof(st1) = %d\n", sizeof(st1)); st1.f1 = 3; @@ -2230,12 +2215,15 @@ double ftab1[3] = { 1.2, 3.4, -5.6 }; void float_test(void) { #if !defined(__arm__) || defined(__ARM_PCS_VFP) - float fa, fb; - double da, db; + volatile float fa, fb; + volatile double da, db; int a; unsigned int b; + static double nan2 = 0.0/0.0; + static double inf1 = 1.0/0.0; + static double inf2 = 1e5000; + volatile LONG_DOUBLE la; - printf("float_test:\n"); printf("sizeof(float) = %d\n", sizeof(float)); printf("sizeof(double) = %d\n", sizeof(double)); printf("sizeof(long double) = %d\n", sizeof(LONG_DOUBLE)); @@ -2255,6 +2243,31 @@ void float_test(void) b = 4000000000; db = b; printf("db = %f\n", db); + printf("nan != nan = %d, inf1 = %f, inf2 = %f\n", nan2 != nan2, inf1, inf2); + da = 0x0.88p-1022; /* a subnormal */ + la = da; + printf ("da subnormal = %a\n", da); + printf ("da subnormal = %.40g\n", da); + printf ("la subnormal = %La\n", la); + printf ("la subnormal = %.40Lg\n", la); + da /= 2; + la = da; + printf ("da/2 subnormal = %a\n", da); + printf ("da/2 subnormal = %.40g\n", da); + printf ("la/2 subnormal = %La\n", la); + printf ("la/2 subnormal = %.40Lg\n", la); + fa = 0x0.88p-126f; /* a subnormal */ + la = fa; + printf ("fa subnormal = %a\n", fa); + printf ("fa subnormal = %.40g\n", fa); + printf ("la subnormal = %La\n", la); + printf ("la subnormal = %.40Lg\n", la); + fa /= 2; + la = fa; + printf ("fa/2 subnormal = %a\n", fa); + printf ("fa/2 subnormal = %.40g\n", fa); + printf ("la/2 subnormal = %La\n", la); + printf ("la/2 subnormal = %.40Lg\n", la); #endif } @@ -2266,6 +2279,12 @@ int fib(int n) return fib(n-1) + fib(n-2); } +#if __GNUC__ == 3 +# define aligned_function 0 +#else +void __attribute__((aligned(16))) aligned_function(int i) {} +#endif + void funcptr_test() { void (*func)(int); @@ -2276,7 +2295,6 @@ void funcptr_test() } st1; long diff; - printf("funcptr:\n"); func = # (*func)(12345); func = num; @@ -2296,6 +2314,10 @@ void funcptr_test() func(42); (func + diff)(42); (num + a)(43); + + /* Check that we can align functions */ + func = aligned_function; + printf("aligned_function (should be zero): %d\n", ((int)(uintptr_t)func) & 15); } void lloptest(long long a, long long b) @@ -2420,12 +2442,16 @@ long long llfunc2(long long x, long long y, int z) return x * y * z; } +void check_opl_save_regs(char *a, long long b, int c) +{ + *a = b < 0 && !c; +} + void longlong_test(void) { long long a, b, c; int ia; unsigned int ua; - printf("longlong_test:\n"); printf("sizeof(long long) = %d\n", sizeof(long long)); ia = -1; ua = -2; @@ -2487,12 +2513,24 @@ void longlong_test(void) a = 0x123; long long *p = &a; llshift(*p, 5); + + /* shortening followed by widening */ + unsigned long long u = 0x8000000000000001ULL; + u = (unsigned)(u + 1); + printf("long long u=" ULONG_LONG_FORMAT "\n", u); + u = 0x11223344aa998877ULL; + u = (unsigned)(int)(u + 1); + printf("long long u=" ULONG_LONG_FORMAT "\n", u); + + /* was a problem with missing save_regs in gen_opl on 32-bit platforms */ + char cc = 78; + check_opl_save_regs(&cc, -1, 0); + printf("check_opl_save_regs: %d\n", cc); } void manyarg_test(void) { LONG_DOUBLE ld = 1234567891234LL; - printf("manyarg_test:\n"); printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n", 1, 2, 3, 4, 5, 6, 7, 8, 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0); @@ -2524,6 +2562,18 @@ void manyarg_test(void) 42.0, 43.0, ld); } +void* +va_arg_with_struct_ptr(va_list ap) { + /* + * This was a BUG identified with FFTW-3.3.8 on arm64. + * The test case only checks it compiles on all supported + * architectures. This function is not currently called. + */ + struct X { int _x; }; + struct X *x = va_arg(ap, struct X *); + return x; +} + void vprintf1(const char *fmt, ...) { va_list ap, aq; @@ -2601,6 +2651,19 @@ void stdarg_for_libc(const char *fmt, ...) va_end(args); } +void stdarg_syntax(int n, ...) +{ + int i; + va_list ap; + if (1) + va_start(ap, n); + else + ; + i = va_arg(ap, int); + printf("stdarg_void_expr: %d\n", i); + (va_end(ap)); +} + void stdarg_test(void) { LONG_DOUBLE ld = 1234567891234LL; @@ -2648,38 +2711,7 @@ void stdarg_test(void) bob.profile = 42; stdarg_for_struct(bob, bob, bob, bob.profile); stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456); -} - -void whitespace_test(void) -{ - char *str; - -
#if 1 - pri\ -ntf("whitspace:\n");
-#endif - pf("N=%d\n", 2); - -#ifdef CORRECT_CR_HANDLING - pri\
-ntf("aaa=%d\n", 3); -#endif - - pri\ -\ -ntf("min=%d\n", 4); - -#ifdef ACCEPT_CR_IN_STRINGS - printf("len1=%d\n", strlen(" -")); -#ifdef CORRECT_CR_HANDLING - str = "
-"; - printf("len1=%d str[0]=%d\n", strlen(str), str[0]); -#endif - printf("len1=%d\n", strlen("
a -")); -#endif /* ACCEPT_CR_IN_STRINGS */ + stdarg_syntax(1, 17); } int reltab[3] = { 1, 2, 3 }; @@ -2738,7 +2770,7 @@ int cmpfn(); printf("cmpfn=%lx\n", (long)cmpfn); } -void old_style_function(void) +void old_style_function_test(void) { old_style_f((void *)1, 2, 3.0); decl_func1(NULL); @@ -2765,7 +2797,7 @@ void *bounds_checking_is_enabled() typedef int constant_negative_array_size_as_compile_time_assertion_idiom[(1 ? 2 : 0) - 1]; -void c99_vla_test(int size1, int size2) +void c99_vla_test_1(int size1, int size2) { #if defined __i386__ || defined __x86_64__ int size = size1 * size2; @@ -2816,9 +2848,11 @@ void c99_vla_test(int size1, int size2) #endif } -#ifndef __TINYC__ -typedef __SIZE_TYPE__ uintptr_t; -#endif +void c99_vla_test(void) +{ + c99_vla_test_1(5, 2); +} + void sizeof_test(void) { @@ -2962,6 +2996,22 @@ void statement_expr_test(void) /* Test that we can give out addresses of local labels. */ consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; })); + + /* Test interaction between local and global label stacks and the + need to defer popping symbol from them when within statement + expressions. Note how the labels are both named LBL. */ + i = 0; + ({ + { + __label__ LBL; + LBL: if (i++ == 0) goto LBL; + } + /* jump to a classical label out of an expr-stmt that had previously + overshadowed that classical label */ + goto LBL; + }); + LBL: + printf("stmtexpr: %d should be 2\n", i); } void local_label_test(void) @@ -3087,6 +3137,8 @@ static __inline__ void sigdelset1(unsigned int *set, int _sig) asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc", "flags"); } +#ifndef __APPLE__ +/* clang's inline asm is uncapable of 'xchgb %b0,%h0' */ static __inline__ __const__ unsigned int swab32(unsigned int x) { __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ @@ -3096,6 +3148,7 @@ static __inline__ __const__ unsigned int swab32(unsigned int x) : "0" (x)); return x; } +#endif static __inline__ unsigned long long mul64(unsigned int a, unsigned int b) { @@ -3172,6 +3225,7 @@ void base_func(void) printf ("asmc: base\n"); } +#ifndef __APPLE__ extern void override_func1 (void); extern void override_func2 (void); @@ -3189,6 +3243,21 @@ void override_func2 (void) extern int bug_table[] __attribute__((section("__bug_table"))); char * get_asm_string (void) { + /* On i386 when -fPIC is enabled this would cause a compile error with GCC, + the problem being the "i" constraint used with a symbolic operand + resolving to a local label. That check is overly zealous as the code + within the asm makes sure to use it only in PIC-possible contexts, + but all GCC versions behave like so. We arrange for PIC to be disabled + for compiling tcctest.c in the Makefile. + + Additionally the usage of 'c' in "%c0" in the template is actually wrong, + as that would expect an operand that is a condition code. The operand + as is (a local label) is accepted by GCC in non-PIC mode, and on x86-64. + What the linux kernel really wanted is 'p' to disable the addition of '$' + to the printed operand (as in "$.LC0" where the template only wants the + bare operand ".LC0"). But the code below is what the linux kernel + happens to use and as such is the one we want to test. */ +#ifndef __clang__ extern int some_symbol; asm volatile (".globl some_symbol\n" "jmp .+6\n" @@ -3204,6 +3273,9 @@ char * get_asm_string (void) ".popsection\n" : : "i" ("A string")); char * str = ((char*)bug_table) + bug_table[1]; return str; +#else + return (char *) "A string"; +#endif } /* This checks another constructs with local labels. */ @@ -3225,6 +3297,7 @@ void asm_local_label_diff (void) { printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]); } +#endif /* This checks that static local variables are available from assembler. */ void asm_local_statics (void) @@ -3255,7 +3328,7 @@ void clobber_r12(void) } #endif -void test_high_clobbers(void) +void test_high_clobbers_really(void) { #if defined __x86_64__ && !defined _WIN64 register long val asm("r12"); @@ -3271,6 +3344,20 @@ void test_high_clobbers(void) #endif } +void test_high_clobbers(void) +{ +#if defined __x86_64__ && !defined _WIN64 + long x1, x2; + asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */ + test_high_clobbers_really(); + asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */ + asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */ + /* should be 0 but tcc doesn't save r12 automatically, which has + bad effects when gcc helds TCCState *s in r12 in tcc.c:main */ + //printf("r12-clobber-diff: %lx\n", x2 - x1); +#endif +} + static long cpu_number; void trace_console(long len, long len2) { @@ -3359,8 +3446,10 @@ void test_asm_call(void) tested here). */ /* two pushes so stack remains aligned */ asm volatile ("push %%rdi; push %%rdi; mov %0, %%rdi;" -#if 1 && !defined(__TINYC__) && (defined(__PIC__) || defined(__PIE__)) +#if 1 && !defined(__TINYC__) && (defined(__PIC__) || defined(__PIE__)) && !defined(__APPLE__) "call getenv@plt;" +#elif defined(__APPLE__) + "call _getenv;" #else "call getenv;" #endif @@ -3378,6 +3467,7 @@ void test_asm_call(void) void asm_dot_test(void) { +#ifndef __APPLE__ int x; for (x = 1;; ++x) { int r = x; @@ -3385,13 +3475,31 @@ void asm_dot_test(void) case 1: asm(".text; lea S"RX",%eax; lea ."RX",%ecx; sub %ecx,%eax; S=.; jmp p0"); case 2: +#ifndef __clang__ + /* clangs internal assembler is broken */ asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0"); +#else + asm(".text; mov $123, %eax; jmp p0"); +#endif case 3: - asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4"); +#if !defined(_WIN32) && !defined(__clang__) + asm(".pushsection \".data\"; Y=.; .int 999; X=Y; .int 456; X=.-4; .popsection"); +#else + asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4; .text"); +#endif asm(".text; mov X"RX",%eax; jmp p0"); case 4: - asm(".data; X=.; .int 789; Y=.; .int 999"); +#ifdef __clang__ + /* Bah! Clang! Doesn't want to redefine 'X' */ + asm(".text; mov $789,%eax; jmp p0"); +#else +#ifndef _WIN32 + asm(".data; X=.; .int 789; Y=.; .int 999; .previous"); +#else + asm(".data; X=.; .int 789; Y=.; .int 999; .text"); +#endif asm(".text; mov X"RX",%eax; X=Y; jmp p0"); +#endif case 0: asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break; } @@ -3399,6 +3507,7 @@ void asm_dot_test(void) break; printf("asm_dot_test %d: %d\n", x, r); } +#endif } void asm_test(void) @@ -3417,8 +3526,6 @@ void asm_test(void) #endif register int regvar asm("%esi"); - printf("inline asm:\n"); - // parse 0x1E-1 as 3 tokens in asm mode asm volatile ("mov $0x1E-1,%eax"); @@ -3452,8 +3559,11 @@ void asm_test(void) __asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc"); printf("set=0x%x\n", set); val = 0x01020304; +#ifndef __APPLE__ printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val)); +#endif #ifndef _WIN32 +#ifndef __APPLE__ override_func1(); override_func2(); /* The base_func ref from the following inline asm should find @@ -3462,13 +3572,17 @@ void asm_test(void) override_func3(); printf("asmstr: %s\n", get_asm_string()); asm_local_label_diff(); +#endif asm_local_statics(); #endif +#ifndef __clang__ + /* clang can't deal with the type change */ /* Check that we can also load structs of appropriate layout into registers. */ asm volatile("" : "=r" (asmret) : "0"(s2)); if (asmret != s2.addr) printf("asmstr: failed\n"); +#endif #ifdef BOOL_ISOC99 /* Check that the typesize correctly sets the register size to 8 bit. */ @@ -3530,11 +3644,24 @@ void builtin_test(void) /* space is needed because tcc preprocessor introduces a space between each token */ COMPAT_TYPE(char * *, void *); #endif - printf("res = %d\n", __builtin_constant_p(1)); - printf("res = %d\n", __builtin_constant_p(1 + 2)); - printf("res = %d\n", __builtin_constant_p(&constant_p_var)); - printf("res = %d\n", __builtin_constant_p(constant_p_var)); - printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var)); + printf("res1 = %d\n", __builtin_constant_p(1)); + printf("res2 = %d\n", __builtin_constant_p(1 + 2)); + printf("res3 = %d\n", __builtin_constant_p(&constant_p_var)); + printf("res4 = %d\n", __builtin_constant_p(constant_p_var)); + printf("res5 = %d\n", __builtin_constant_p(100000 / constant_p_var)); +#ifdef __clang__ + /* clang doesn't regard this as constant expression */ + printf("res6 = 1\n"); +#else + printf("res6 = %d\n", __builtin_constant_p(i && 0)); +#endif + printf("res7 = %d\n", __builtin_constant_p(i && 1)); +#ifdef __clang__ + /* clang doesn't regard this as constant expression */ + printf("res8 = 1\n"); +#else + printf("res8 = %d\n", __builtin_constant_p(i && 0 ? i : 34)); +#endif s = 1; ll = 2; i = __builtin_choose_expr (1 != 0, ll, s); @@ -3549,7 +3676,9 @@ void builtin_test(void) //printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); } -#ifndef _WIN32 +#ifdef _WIN32 +void weak_test(void) {} +#else extern int __attribute__((weak)) weak_f1(void); extern int __attribute__((weak)) weak_f2(void); extern int weak_f3(void); @@ -3568,14 +3697,18 @@ extern int weak_asm_v1 asm("weak_asm_v1x") __attribute extern int __attribute((weak)) weak_asm_v2 asm("weak_asm_v2x") ; extern int __attribute((weak)) weak_asm_v3(void) asm("weak_asm_v3x") __attribute((weak)); +#ifndef __clang__ static const size_t dummy = 0; extern __typeof(dummy) weak_dummy1 __attribute__((weak, alias("dummy"))); extern __typeof(dummy) __attribute__((weak, alias("dummy"))) weak_dummy2; extern __attribute__((weak, alias("dummy"))) __typeof(dummy) weak_dummy3; +#endif int some_lib_func(void); int dummy_impl_of_slf(void) { return 444; } +#ifndef __clang__ int some_lib_func(void) __attribute__((weak, alias("dummy_impl_of_slf"))); +#endif int weak_toolate() __attribute__((weak)); int weak_toolate() { return 0; } @@ -3599,7 +3732,11 @@ void __attribute__((weak)) weak_test(void) printf("weak_asm_v1=%d\n",&weak_asm_v1 != NULL); printf("weak_asm_v2=%d\n",&weak_asm_v2 != NULL); printf("weak_asm_v3=%d\n",&weak_asm_v3 != NULL); +#ifdef __clang__ + printf("some_lib_func=444\n"); +#else printf("some_lib_func=%d\n", &some_lib_func ? some_lib_func() : 0); +#endif } int __attribute__((weak)) weak_f2() { return 222; } @@ -3695,6 +3832,7 @@ int fcompare (double a, double b, int code) case 4: return a > b; case 5: return a <= b; } + return 0; } void math_cmp_test(void) @@ -3703,6 +3841,7 @@ void math_cmp_test(void) double one = 1.0; double two = 2.0; int comp = 0; + int v; #define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part) /* This asserts that "a op b" is _not_ true, but "a iop b" is true. @@ -3724,7 +3863,8 @@ void math_cmp_test(void) if ((a iop b) || comp) \ ; \ else \ - bug (a,b,op,iop,5); + bug (a,b,op,iop,5); \ + if (v = !(a op b), !v) bug(a,b,op,iop,7); /* Equality tests. */ FCMP(nan, nan, ==, !=, 0); @@ -3793,8 +3933,10 @@ void builtin_frame_address_test(void) char *fp0 = __builtin_frame_address(0); printf("str: %s\n", str); +#ifndef __riscv bfa1(str-fp0); #endif +#endif } char via_volatile (char i) @@ -3804,6 +3946,14 @@ char via_volatile (char i) return vi; } +void volatile_test(void) +{ + if (via_volatile (42) != 42) + printf (" broken\n"); + else + printf (" ok\n"); +} + struct __attribute__((__packed__)) Spacked { char a; short b; @@ -3869,3 +4019,137 @@ int force_get_order(unsigned long s) { return __get_order(s); } + +#define pv(m) printf(sizeof (s->m + 0) == 8 ? "%016llx\n" : "%02x\n", s->m) + +/* Test failed when using bounds checking */ +void bounds_check1_test (void) +{ + struct s { + int x; + long long y; + } _s, *s = &_s; + s->x = 10; + s->y = 20; + pv(x); + pv(y); +} + +/* gcc 2.95.3 does not handle correctly CR in strings or after strays */ +#define CORRECT_CR_HANDLING + +/* deprecated and no longer supported in gcc 3.3 */ +#ifdef __TINYC__ +# define ACCEPT_CR_IN_STRINGS +#endif + +/* keep this as the last test because GCC messes up line-numbers + with the ^L^K^M characters below */ +void whitespace_test(void) +{ + char *str; + +
#if 1 + pri\ +ntf("whitspace:\n");
+#endif + pf("N=%d\n", 2); + +#ifdef CORRECT_CR_HANDLING + pri\
+ntf("aaa=%d\n", 3); +#endif + + pri\ +\ +ntf("min=%d\n", 4); + +#ifdef ACCEPT_CR_IN_STRINGS + printf("len1=%d\n", strlen(" +")); +#ifdef CORRECT_CR_HANDLING + str = "
+"; + printf("len1=%d str[0]=%d\n", strlen(str), str[0]); +#endif + printf("len1=%d\n", strlen("
a +")); +#else + printf("len1=1\nlen1=1 str[0]=10\nlen1=3\n"); +#endif /* ACCEPT_CR_IN_STRINGS */ + +#ifdef __LINE__ + printf("__LINE__ defined\n"); +#endif + +#if 0 + /* wrong with GCC */ + printf("__LINE__=%d __FILE__=%s\n", __LINE__, __FILE__); +#line 1111 + printf("__LINE__=%d __FILE__=%s\n", __LINE__, __FILE__); +#line 2222 "test" + printf("__LINE__=%d __FILE__=%s\n", __LINE__, __FILE__); +#endif +} + +#define RUN(test) puts("---- " #test " ----"), test(), puts("") + +int main(int argc, char **argv) +{ + RUN(whitespace_test); + RUN(macro_test); + RUN(recursive_macro_test); + RUN(string_test); + RUN(expr_test); + RUN(scope_test); + RUN(scope2_test); + RUN(forward_test); + RUN(funcptr_test); + RUN(if_test); + RUN(loop_test); + RUN(switch_test); + RUN(goto_test); + RUN(enum_test); + RUN(typedef_test); + RUN(struct_test); + RUN(array_test); + RUN(expr_ptr_test); + RUN(bool_test); + RUN(optimize_out_test); + RUN(expr2_test); + RUN(constant_expr_test); + RUN(expr_cmp_test); + RUN(char_short_test); + RUN(init_test); + RUN(compound_literal_test); + RUN(kr_test); + RUN(struct_assign_test); + RUN(cast_test); + RUN(bitfield_test); + RUN(c99_bool_test); + RUN(float_test); + RUN(longlong_test); + RUN(manyarg_test); + RUN(stdarg_test); + RUN(relocation_test); + RUN(old_style_function_test); + RUN(alloca_test); + RUN(c99_vla_test); + RUN(sizeof_test); + RUN(typeof_test); + RUN(statement_expr_test); + RUN(local_label_test); + RUN(asm_test); + RUN(builtin_test); + RUN(weak_test); + RUN(global_data_test); + RUN(cmp_comparison_test); + RUN(math_cmp_test); + RUN(callsave_test); + RUN(builtin_frame_address_test); + RUN(volatile_test); + RUN(attrib_test); + RUN(bounds_check1_test); + + return 0; +} diff --git a/tests/tests2/03_struct.c b/tests/tests2/03_struct.c index c5d48c5..fd73133 100644 --- a/tests/tests2/03_struct.c +++ b/tests/tests2/03_struct.c @@ -1,6 +1,13 @@ -#include <stdio.h> +extern int printf(const char*, ...); -struct fred +struct fred; + +void fred$(struct fred* this) +{ + printf("~fred()\n"); +} + +struct __attribute__((__cleanup__(fred$))) fred { int boris; int natasha; @@ -8,7 +15,7 @@ struct fred int main() { - struct fred bloggs; + struct fred __attribute__((__cleanup__(fred$))) bloggs; bloggs.boris = 12; bloggs.natasha = 34; diff --git a/tests/tests2/03_struct.expect b/tests/tests2/03_struct.expect index ecbf589..be8df37 100644 --- a/tests/tests2/03_struct.expect +++ b/tests/tests2/03_struct.expect @@ -1,6 +1,8 @@ +03_struct.c:14: warning: attribute '__cleanup__' ignored on type 12 34 12 34 56 78 +~fred() diff --git a/tests/tests2/07_function.c b/tests/tests2/07_function.c index 0477ce1..006e0a7 100644 --- a/tests/tests2/07_function.c +++ b/tests/tests2/07_function.c @@ -15,6 +15,11 @@ void qfunc() printf("qfunc()\n"); } +void zfunc() +{ + ((void (*)(void))0) (); +} + int main() { printf("%d\n", myfunc(3)); diff --git a/tests/tests2/100_c99array-decls.c b/tests/tests2/100_c99array-decls.c new file mode 100644 index 0000000..46950aa --- /dev/null +++ b/tests/tests2/100_c99array-decls.c @@ -0,0 +1,34 @@ +void foo(int [5]); +void fooc(int x[const 5]); +void foos(int x[static 5]); +void foov(int x[volatile 5]); +void foor(int x[restrict 5]); +void fooc(int [const 5]); +void foos(int [static 5]); +void foov(int [volatile 5]); +void foor(int [restrict 5]); +void fooc(int (* const x)); +void foos(int *x); +void foov(int * volatile x); +void foor(int * restrict x); +void fooc(int x[volatile 5]) +{ + x[3] = 42; +#ifdef INVALID + x = 0; +#endif +} +void foovm(int x[const *]); +void foovm(int * const x); +#ifdef INVALID +void wrongc(int x[3][const 4]); +void wrongvm(int x[static *]); +void foovm(int x[const *]) +{ + x[2] = 1; +} +#endif +int main() +{ + return 0; +} diff --git a/tests/tests2/100_c99array-decls.expect b/tests/tests2/100_c99array-decls.expect new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/tests2/100_c99array-decls.expect diff --git a/tests/tests2/101_cleanup.c b/tests/tests2/101_cleanup.c new file mode 100644 index 0000000..de5dca2 --- /dev/null +++ b/tests/tests2/101_cleanup.c @@ -0,0 +1,227 @@ +extern int printf(const char*, ...); +static int glob_i = 0; + +void incr_glob_i(int *i) +{ + glob_i += *i; +} + +#define INCR_GI { \ + int i __attribute__ ((__cleanup__(incr_glob_i))) = 1; \ + } + +#define INCR_GI0 INCR_GI INCR_GI INCR_GI INCR_GI +#define INCR_GI1 INCR_GI0 INCR_GI0 INCR_GI0 INCR_GI0 +#define INCR_GI2 INCR_GI1 INCR_GI1 INCR_GI1 INCR_GI1 +#define INCR_GI3 INCR_GI2 INCR_GI2 INCR_GI2 INCR_GI2 +#define INCR_GI4 INCR_GI3 INCR_GI3 INCR_GI3 INCR_GI3 +#define INCR_GI5 INCR_GI4 INCR_GI4 INCR_GI4 INCR_GI4 +#define INCR_GI6 INCR_GI5 INCR_GI5 INCR_GI5 INCR_GI5 +#define INCR_GI7 INCR_GI6 INCR_GI6 INCR_GI6 INCR_GI6 + + +void check2(char **hum); + +void check(int *j) +{ + char * __attribute__ ((cleanup(check2))) stop_that = "wololo"; + int chk = 0; + + { + char * __attribute__ ((cleanup(check2))) stop_that = "plop"; + + { + non_plopage: + printf("---- %d\n", chk); + } + if (!chk) { + chk = 1; + goto non_plopage; + } + } + + { + char * __attribute__ ((cleanup(check2))) stop_that = "tata !"; + + goto out; + stop_that = "titi"; + } + again: + chk = 2; + { + char * __attribute__ ((cleanup(check2))) cascade1 = "1"; + { + char * __attribute__ ((cleanup(check2))) cascade2 = "2"; + { + char * __attribute__ ((cleanup(check2))) cascade3 = "3"; + + goto out; + cascade3 = "nope"; + } + } + } + out: + if (chk != 2) + goto again; + { + { + char * __attribute__ ((cleanup(check2))) out = "last goto out"; + ++chk; + if (chk != 3) + goto out; + } + } + return; +} + +void check_oh_i(char *oh_i) +{ + printf("c: %c\n", *oh_i); +} + +void goto_hell(double *f) +{ + printf("oo: %f\n", *f); +} + +char *test() +{ + char *__attribute__ ((cleanup(check2))) str = "I don't think this should be print(but gcc got it wrong too)"; + + return str; +} + +void test_ret_subcall(char *that) +{ + printf("should be print before\n"); +} + +void test_ret() +{ + char *__attribute__ ((cleanup(check2))) that = "that"; + return test_ret_subcall(that); +} + +void test_ret2() +{ + char *__attribute__ ((cleanup(check2))) that = "-that"; + { + char *__attribute__ ((cleanup(check2))) that = "this should appear only once"; + } + { + char *__attribute__ ((cleanup(check2))) that = "-that2"; + return; + } +} + +void test2(void) { + int chk = 0; +again: + if (!chk) { + char * __attribute__ ((cleanup(check2))) stop_that = "test2"; + chk++; + goto again; + } +} + +int test3(void) { + char * __attribute__ ((cleanup(check2))) stop_that = "three"; + int chk = 0; + + if (chk) { + { + outside: + { + char * __attribute__ ((cleanup(check2))) stop_that = "two"; + printf("---- %d\n", chk); + } + } + } + if (!chk) + { + char * __attribute__ ((cleanup(check2))) stop_that = "one"; + + if (!chk) { + chk = 1; + goto outside; + } + } + return 0; +} + +void cl(int *ip) +{ + printf("%d\n", *ip); +} + +void loop_cleanups(void) +{ + __attribute__((cleanup(cl))) int l = 1000; + + printf("-- loop 0 --\n"); + for ( __attribute__((cleanup(cl))) int i = 0; i < 10; ++i) { + __attribute__((cleanup(cl))) int j = 100; + } + + printf("-- loop 1 --\n"); + for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) { + __attribute__((cleanup(cl))) int j = 200; + continue; + } + + printf("-- loop 2 --\n"); + for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) { + __attribute__((cleanup(cl))) int j = 300; + break; + } + + printf("-- loop 3 --\n"); + for (int i = 0; i < 2; ++i) { + __attribute__((cleanup(cl))) int j = 400; + switch (i) { + case 0: + continue; + default: + { + __attribute__((cleanup(cl))) int jj = 500; + break; + } + } + } + printf("after break\n"); +} + +int main() +{ + int i __attribute__ ((__cleanup__(check))) = 0, not_i; + int chk = 0; + (void)not_i; + + { + __attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a'; + } + + INCR_GI7; + printf("glob_i: %d\n", glob_i); + naaaaaaaa: + if (!chk) { + __attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'f'; + double __attribute__ ((__cleanup__(goto_hell))) f = 2.6; + + chk = 1; + goto naaaaaaaa; + } + i = 105; + printf("because what if free was call inside cleanup function %s\n", test()); + test_ret(); + test_ret2(); + test2(); + test3(); + loop_cleanups(); + return i; +} + +void check2(char **hum) +{ + printf("str: %s\n", *hum); +} diff --git a/tests/tests2/101_cleanup.expect b/tests/tests2/101_cleanup.expect new file mode 100644 index 0000000..84960cd --- /dev/null +++ b/tests/tests2/101_cleanup.expect @@ -0,0 +1,59 @@ +c: a +c: o +glob_i: 65536 +oo: 2.600000 +c: f +str: I don't think this should be print(but gcc got it wrong too) +because what if free was call inside cleanup function I don't think this should be print(but gcc got it wrong too) +should be print before +str: that +str: this should appear only once +str: -that2 +str: -that +str: test2 +str: one +---- 1 +str: two +str: three +-- loop 0 -- +100 +100 +100 +100 +100 +100 +100 +100 +100 +100 +10 +-- loop 1 -- +200 +200 +200 +200 +200 +200 +200 +200 +200 +200 +10 +-- loop 2 -- +300 +0 +-- loop 3 -- +400 +500 +400 +after break +1000 +---- 0 +---- 1 +str: plop +str: tata ! +str: 3 +str: 2 +str: 1 +str: last goto out +str: wololo diff --git a/tests/tests2/102_alignas.c b/tests/tests2/102_alignas.c new file mode 100644 index 0000000..62d3ed2 --- /dev/null +++ b/tests/tests2/102_alignas.c @@ -0,0 +1,29 @@ +_Alignas(16) int i1; +int _Alignas(16) i2; +void _Alignas(16) *p2; +_Alignas(16) i3; +int _Alignas(double) i4; +int _Alignas(int) i5; +#if 0 +/* The following are currently wrongly accepted by TCC but really shouldn't. */ +int _Alignas(int _Alignas(16)) i6; //wrong, 'int _Alignas(16)' is no type-name +typedef int _Alignas(16) int16aligned_t; //wrong, _Alignas invalid on typedef +int16aligned_t i7; +#endif +/* i8 should get an alignment of 16, because unlike _Alignas the + corresponding attribute _does_ apply to type-name, though not in + some clang versions. */ +int _Alignas(int __attribute__((aligned(16)))) i8; +extern int printf(const char*, ...); +#ifdef _MSC_VER +#define alignof(x) (int)__alignof(x) +#else +#define alignof(x) (int)__alignof__(x) +#endif +int main() +{ + printf("%d %d %d %d\n", + alignof(i1) == 16, alignof(i4) == alignof(double), + alignof(i5) == alignof(int) , alignof(i8) == 16); + return 0; +} diff --git a/tests/tests2/102_alignas.expect b/tests/tests2/102_alignas.expect new file mode 100644 index 0000000..ac6474a --- /dev/null +++ b/tests/tests2/102_alignas.expect @@ -0,0 +1 @@ +1 1 1 1 diff --git a/tests/tests2/103_implicit_memmove.c b/tests/tests2/103_implicit_memmove.c new file mode 100644 index 0000000..1592fb2 --- /dev/null +++ b/tests/tests2/103_implicit_memmove.c @@ -0,0 +1,20 @@ +/* Test that the memmove TCC is emitting for the struct copy + and hence implicitely declares can be declared properly also + later. */ +struct S { int a,b,c,d, e[1024];}; +int foo (struct S *a, struct S *b) +{ + *a = *b; + return 0; +} + +void *memmove(void*,const void*,__SIZE_TYPE__); +void foo2 (struct S *a, struct S *b) +{ + memmove(a, b, sizeof *a); +} + +int main() +{ + return 0; +} diff --git a/tests/tests2/103_implicit_memmove.expect b/tests/tests2/103_implicit_memmove.expect new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/tests2/103_implicit_memmove.expect diff --git a/tests/tests2/104+_inline.c b/tests/tests2/104+_inline.c new file mode 100644 index 0000000..1209fd4 --- /dev/null +++ b/tests/tests2/104+_inline.c @@ -0,0 +1,54 @@ + +#define GOT(f) \ + __attribute__((weak)) void f(void); \ + printf("%d %s\n", !!f, #f); + +int printf(const char*, ...); + +void check_exports() +{ + // 0 + GOT(inline_inline_2decl_only) + GOT(inline_inline_undeclared) + GOT(inline_inline_predeclared) + GOT(inline_inline_postdeclared) + GOT(inline_inline_prepostdeclared) + GOT(inline_inline_undeclared2) + GOT(inline_inline_predeclared2) + GOT(inline_inline_postdeclared2) + GOT(inline_inline_prepostdeclared2) + + // 1 + GOT(extern_extern_postdeclared) + GOT(extern_extern_postdeclared2) + GOT(extern_extern_predeclared) + GOT(extern_extern_predeclared2) + GOT(extern_extern_prepostdeclared) + GOT(extern_extern_prepostdeclared2) + GOT(extern_extern_undeclared) + GOT(extern_extern_undeclared2) + GOT(extern_postdeclared) + GOT(extern_postdeclared2) + GOT(extern_predeclared) + GOT(extern_predeclared2) + GOT(extern_prepostdeclared) + GOT(extern_undeclared) + GOT(extern_undeclared2) + GOT(inst2_extern_inline_postdeclared) + GOT(inst2_extern_inline_predeclared) + GOT(inst3_extern_inline_predeclared) + GOT(inst_extern_inline_postdeclared) + GOT(inst_extern_inline_predeclared) + GOT(main) + GOT(noinst_extern_inline_func) + GOT(noinst_extern_inline_postdeclared) + GOT(noinst_extern_inline_postdeclared2) + GOT(noinst_extern_inline_undeclared) + + // 0 + GOT(noinst_static_inline_postdeclared) + GOT(noinst2_static_inline_postdeclared) + GOT(noinst_static_inline_predeclared) + GOT(noinst2_static_inline_predeclared) + GOT(static_func) +} diff --git a/tests/tests2/104_inline.c b/tests/tests2/104_inline.c new file mode 100644 index 0000000..766f94a --- /dev/null +++ b/tests/tests2/104_inline.c @@ -0,0 +1,132 @@ +inline void inline_inline_2decl_only(void); +inline void inline_inline_2decl_only(void); + +inline void inline_inline_undeclared(void){} + +inline void inline_inline_predeclared(void); +inline void inline_inline_predeclared(void){} + +inline void inline_inline_postdeclared(void){} +inline void inline_inline_postdeclared(void); + +inline void inline_inline_prepostdeclared(void); +inline void inline_inline_prepostdeclared(void){} +inline void inline_inline_prepostdeclared(void); + +inline void inline_inline_undeclared2(void){} + +inline void inline_inline_predeclared2(void); +inline void inline_inline_predeclared2(void); +inline void inline_inline_predeclared2(void){} + +inline void inline_inline_postdeclared2(void){} +inline void inline_inline_postdeclared2(void); +inline void inline_inline_postdeclared2(void); + +inline void inline_inline_prepostdeclared2(void); +inline void inline_inline_prepostdeclared2(void); +inline void inline_inline_prepostdeclared2(void){} +inline void inline_inline_prepostdeclared2(void); +inline void inline_inline_prepostdeclared2(void); + +extern void extern_extern_undeclared(void){} + +extern void extern_extern_predeclared(void); +extern void extern_extern_predeclared(void){} + +extern void extern_extern_postdeclared(void){} +extern void extern_extern_postdeclared(void); + +extern void extern_extern_prepostdeclared(void); +extern void extern_extern_prepostdeclared(void){} +extern void extern_extern_prepostdeclared(void); + +extern void extern_extern_undeclared2(void){} + +extern void extern_extern_predeclared2(void); +extern void extern_extern_predeclared2(void); +extern void extern_extern_predeclared2(void){} + +extern void extern_extern_postdeclared2(void){} +extern void extern_extern_postdeclared2(void); +extern void extern_extern_postdeclared2(void); + +extern void extern_extern_prepostdeclared2(void); +extern void extern_extern_prepostdeclared2(void); +extern void extern_extern_prepostdeclared2(void){} +extern void extern_extern_prepostdeclared2(void); +extern void extern_extern_prepostdeclared2(void); + +void extern_undeclared(void){} + +void extern_predeclared(void); +void extern_predeclared(void){} + +void extern_postdeclared(void){} +void extern_postdeclared(void); + +void extern_prepostdeclared(void); +void extern_prepostdeclared(void){} +void extern_prepostdeclared(void); + +void extern_undeclared2(void){} + +void extern_predeclared2(void); +void extern_predeclared2(void); +void extern_predeclared2(void){} + +void extern_postdeclared2(void){} +void extern_postdeclared2(void); +void extern_postdeclared2(void); + + +extern inline void noinst_extern_inline_undeclared(void){} + +extern inline void noinst_extern_inline_postdeclared(void){} +inline void noinst_extern_inline_postdeclared(void); + +extern inline void noinst_extern_inline_postdeclared2(void){} +inline void noinst_extern_inline_postdeclared2(void); +inline void noinst_extern_inline_postdeclared2(void); + +extern inline void inst_extern_inline_postdeclared(void){} +extern inline void inst_extern_inline_postdeclared(void); +inline void inst2_extern_inline_postdeclared(void){} +void inst2_extern_inline_postdeclared(void); + +void inst_extern_inline_predeclared(void); +extern inline void inst_extern_inline_predeclared(void){} +void inst2_extern_inline_predeclared(void); +inline void inst2_extern_inline_predeclared(void){} +extern inline void inst3_extern_inline_predeclared(void); +inline void inst3_extern_inline_predeclared(void){} + +static inline void noinst_static_inline_postdeclared(void){} +static inline void noinst_static_inline_postdeclared(void); +static inline void noinst2_static_inline_postdeclared(void){} +static void noinst2_static_inline_postdeclared(void); + +static void noinst_static_inline_predeclared(void); +static inline void noinst_static_inline_predeclared(void){} +static void noinst2_static_inline_predeclared(void); +static inline void noinst2_static_inline_predeclared(void){} + +static void static_func(void); +void static_func(void) { } + +inline void noinst_extern_inline_func(void); +void noinst_extern_inline_func(void) { } + +int main() +{ + inline_inline_undeclared(); inline_inline_predeclared(); inline_inline_postdeclared(); + inline_inline_undeclared2(); inline_inline_predeclared2(); inline_inline_postdeclared2(); + noinst_static_inline_predeclared(); + noinst2_static_inline_predeclared(); + noinst_static_inline_predeclared(); + noinst2_static_inline_predeclared(); + + void check_exports(); + check_exports(); + return 0; +} diff --git a/tests/tests2/104_inline.expect b/tests/tests2/104_inline.expect new file mode 100644 index 0000000..bdb0994 --- /dev/null +++ b/tests/tests2/104_inline.expect @@ -0,0 +1,39 @@ +0 inline_inline_2decl_only +0 inline_inline_undeclared +0 inline_inline_predeclared +0 inline_inline_postdeclared +0 inline_inline_prepostdeclared +0 inline_inline_undeclared2 +0 inline_inline_predeclared2 +0 inline_inline_postdeclared2 +0 inline_inline_prepostdeclared2 +1 extern_extern_postdeclared +1 extern_extern_postdeclared2 +1 extern_extern_predeclared +1 extern_extern_predeclared2 +1 extern_extern_prepostdeclared +1 extern_extern_prepostdeclared2 +1 extern_extern_undeclared +1 extern_extern_undeclared2 +1 extern_postdeclared +1 extern_postdeclared2 +1 extern_predeclared +1 extern_predeclared2 +1 extern_prepostdeclared +1 extern_undeclared +1 extern_undeclared2 +1 inst2_extern_inline_postdeclared +1 inst2_extern_inline_predeclared +1 inst3_extern_inline_predeclared +1 inst_extern_inline_postdeclared +1 inst_extern_inline_predeclared +1 main +1 noinst_extern_inline_func +1 noinst_extern_inline_postdeclared +1 noinst_extern_inline_postdeclared2 +1 noinst_extern_inline_undeclared +0 noinst_static_inline_postdeclared +0 noinst2_static_inline_postdeclared +0 noinst_static_inline_predeclared +0 noinst2_static_inline_predeclared +0 static_func diff --git a/tests/tests2/105_local_extern.c b/tests/tests2/105_local_extern.c new file mode 100644 index 0000000..a248bb4 --- /dev/null +++ b/tests/tests2/105_local_extern.c @@ -0,0 +1,12 @@ +extern int printf(const char *, ...); +void f(void); +void bar(void) { void f(void); f(); } +void foo(void) { extern void f(void); f(); } +void f(void) { printf("f\n"); } + +int main() +{ + bar(); + foo(); + return 0; +} diff --git a/tests/tests2/105_local_extern.expect b/tests/tests2/105_local_extern.expect new file mode 100644 index 0000000..445ae74 --- /dev/null +++ b/tests/tests2/105_local_extern.expect @@ -0,0 +1,2 @@ +f +f diff --git a/tests/tests2/106_pthread.c b/tests/tests2/106_pthread.c new file mode 100644 index 0000000..09308ed --- /dev/null +++ b/tests/tests2/106_pthread.c @@ -0,0 +1,17 @@ +#include <stdio.h> +#include <pthread.h> +#include <errno.h> + +int +main(void) +{ + int ret; + pthread_condattr_t attr; + pthread_cond_t condition; + + pthread_condattr_init (&attr); + pthread_condattr_setpshared (&attr, PTHREAD_PROCESS_SHARED); + printf ("%s\n", pthread_cond_init (&condition, &attr) ? "fail":"ok"); + pthread_condattr_destroy (&attr); + return 0; +} diff --git a/tests/tests2/106_pthread.expect b/tests/tests2/106_pthread.expect new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/tests/tests2/106_pthread.expect @@ -0,0 +1 @@ +ok diff --git a/tests/tests2/107_stack_safe.c b/tests/tests2/107_stack_safe.c new file mode 100644 index 0000000..479c84d --- /dev/null +++ b/tests/tests2/107_stack_safe.c @@ -0,0 +1,13 @@ +extern int printf(const char *, ...); + +static void func_ull_ull(unsigned long long l1,unsigned long long l2){ +} + +int main() +{ + int a,b,c,d; + a=1;b=2;c=3;d=4; + func_ull_ull((unsigned long long)a/1.0,(unsigned long long)b/1.0); + printf("%d %d %d %d",a,b,c,d); + return 0; +} diff --git a/tests/tests2/107_stack_safe.expect b/tests/tests2/107_stack_safe.expect new file mode 100644 index 0000000..e9e9cd7 --- /dev/null +++ b/tests/tests2/107_stack_safe.expect @@ -0,0 +1 @@ +1 2 3 4
\ No newline at end of file diff --git a/tests/tests2/108_constructor.c b/tests/tests2/108_constructor.c new file mode 100644 index 0000000..145d0da --- /dev/null +++ b/tests/tests2/108_constructor.c @@ -0,0 +1,20 @@ +extern int write (int fd, void *buf, int len); + +static void __attribute__ ((constructor)) +testc (void) +{ + write (1, "constructor\n", 12); +} + +static void __attribute__ ((destructor)) +testd (void) +{ + write (1, "destructor\n", 11); +} + +int +main (void) +{ + write (1, "main\n", 5); + return 0; +} diff --git a/tests/tests2/108_constructor.expect b/tests/tests2/108_constructor.expect new file mode 100644 index 0000000..167ca51 --- /dev/null +++ b/tests/tests2/108_constructor.expect @@ -0,0 +1,3 @@ +constructor +main +destructor diff --git a/tests/tests2/109_float_struct_calling.c b/tests/tests2/109_float_struct_calling.c new file mode 100644 index 0000000..90fc045 --- /dev/null +++ b/tests/tests2/109_float_struct_calling.c @@ -0,0 +1,24 @@ +#include <stdio.h> + +/* This test used to fail on x86_64 on linux with sse registers */ + +struct Point { + float x; + float y; +}; + +struct Rect { + struct Point top_left; + struct Point size; +}; + +float foo(struct Point p, struct Rect r) { + return r.size.x; +} + +int main(int argc, char **argv) { + struct Point p = {1, 2}; + struct Rect r = {{3, 4}, {5, 6}}; + printf("%f\n", foo(p, r)); + return 0; +} diff --git a/tests/tests2/109_float_struct_calling.expect b/tests/tests2/109_float_struct_calling.expect new file mode 100644 index 0000000..eaa6787 --- /dev/null +++ b/tests/tests2/109_float_struct_calling.expect @@ -0,0 +1 @@ +5.000000 diff --git a/tests/tests2/110_average.c b/tests/tests2/110_average.c new file mode 100644 index 0000000..273b511 --- /dev/null +++ b/tests/tests2/110_average.c @@ -0,0 +1,27 @@ +#include <stdio.h> + +typedef struct +{ + double average; + int count; +} +stats_type; + +static void +testc (stats_type *s, long long data) +{ + s->average = (s->average * s->count + data) / (s->count + 1); + s->count++; +} + +int main (void) +{ + stats_type s; + + s.average = 0; + s.count = 0; + testc (&s, 10); + testc (&s, 20); + printf ("%g %d\n", s.average, s.count); + return 0; +} diff --git a/tests/tests2/110_average.expect b/tests/tests2/110_average.expect new file mode 100644 index 0000000..4955335 --- /dev/null +++ b/tests/tests2/110_average.expect @@ -0,0 +1 @@ +15 2 diff --git a/tests/tests2/111_conversion.c b/tests/tests2/111_conversion.c new file mode 100644 index 0000000..c0815e1 --- /dev/null +++ b/tests/tests2/111_conversion.c @@ -0,0 +1,22 @@ +#include <stdio.h> + +union u { + unsigned long ul; + long double ld; +}; + +void +conv (union u *p) +{ + p->ul = (unsigned int) p->ld; +} + +int main (void) +{ + union u v; + + v.ld = 42; + conv (&v); + printf ("%lu\n", v.ul); + return 0; +} diff --git a/tests/tests2/111_conversion.expect b/tests/tests2/111_conversion.expect new file mode 100644 index 0000000..d81cc07 --- /dev/null +++ b/tests/tests2/111_conversion.expect @@ -0,0 +1 @@ +42 diff --git a/tests/tests2/112_backtrace.c b/tests/tests2/112_backtrace.c new file mode 100644 index 0000000..8489bd3 --- /dev/null +++ b/tests/tests2/112_backtrace.c @@ -0,0 +1,165 @@ +#include <stdio.h> + +/* ------------------------------------------------------- */ +#if defined test_backtrace_1 + +void f3() +{ + printf("* f3()\n"), fflush(stdout); + *(void**)0 = 0; +} +void f2() +{ + printf("* f2()\n"), fflush(stdout); + f3(); +} +void f1() +{ + printf("* f1()\n"), fflush(stdout); + f2(); +} +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + f1(); + printf("* exit main\n"), fflush(stdout); + return 0; +} + +/* ------------------------------------------------------- */ +#elif defined test_bcheck_1 + +struct s { int a,b,c,d,e; }; +struct s s[3]; +struct s *ps = s; +void f1() +{ + printf("* f1()\n"), fflush(stdout); + ps[3] = ps[2]; +} +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + f1(); + printf("* exit main\n"), fflush(stdout); + return 0; +} + +/* ------------------------------------------------------- */ +#elif defined test_tcc_backtrace_2 + +/* test custom backtrace and 'exit()' redirection */ +int tcc_backtrace(const char *fmt, ...); +void exit(int); + +void f2() +{ + printf("* f2()\n"); + printf("* exit f2\n"), fflush(stdout); + exit(34); +} +void f1() +{ + printf("* f1()\n"), fflush(stdout); + tcc_backtrace("Hello from %s!", "f1"); + f2(); +} +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + f1(); + printf("* exit main\n"), fflush(stdout); + return 0; +} + +/* ------------------------------------------------------- */ +#elif defined test_tcc_backtrace_3 + +/* this test should be run despite of the exit(34) above */ +int main(int argc, char **argv) +{ + printf("* main\n"), fflush(stdout); + return 1; +} + +/* ------------------------------------------------------- */ +#else +#include <stdlib.h> +#include <string.h> +char *strdup(); +int main() +{ + char pad1[10]; + char a[10]; + char pad2[10]; + char b[10]; + char pad3[10]; + memset (pad1, 0, sizeof(pad1)); + memset (pad2, 0, sizeof(pad2)); + memset (pad3, 0, sizeof(pad3)); + + memset (a, 'a', 10); + a[3] = 0; + a[9] = 0; + memset (b, 'b', 10); + +#if defined test_bcheck_100 + memcpy(&a[1],&b[0],10); +#elif defined test_bcheck_101 + memcpy(&a[0],&b[1],10); +#elif defined test_bcheck_102 + memcpy(&a[0],&a[3],4); +#elif defined test_bcheck_103 + memcpy(&a[3],&a[0],4); +#elif defined test_bcheck_104 + memcmp(&b[1],&b[0],10); +#elif defined test_bcheck_105 + memcmp(&b[0],&b[1],10); +#elif defined test_bcheck_106 + memmove(&b[1],&b[0],10); +#elif defined test_bcheck_107 + memmove(&b[0],&b[1],10); +#elif defined test_bcheck_108 + memset(&b[1],'b',10); +#elif defined test_bcheck_109 + strlen(&b[0]); +#elif defined test_bcheck_110 + strcpy(&a[7], &a[0]); +#elif defined test_bcheck_111 + strcpy(&a[0], &b[7]); +#elif defined test_bcheck_112 + strcpy(&a[0], &a[1]); +#elif defined test_bcheck_113 + strcpy(&a[2], &a[0]); +#elif defined test_bcheck_114 + strncpy(&a[7], &a[0], 10); +#elif defined test_bcheck_115 + strncpy(&a[0], &b[7], 10); +#elif defined test_bcheck_116 + strncpy(&a[0], &a[1], 10); +#elif defined test_bcheck_117 + strncpy(&a[2], &a[0], 10); +#elif defined test_bcheck_118 + strcmp(&b[2], &b[0]); +#elif defined test_bcheck_119 + strcmp(&b[0], &b[2]); +#elif defined test_bcheck_120 + strncmp(&b[5], &b[0], 10); +#elif defined test_bcheck_121 + strncmp(&b[0], &b[5], 10); +#elif defined test_bcheck_122 + strcat(&a[7], &a[0]); +#elif defined test_bcheck_123 + strcat(&a[0], &b[3]); +#elif defined test_bcheck_124 + strcat(&a[0], &a[4]); +#elif defined test_bcheck_125 + strcat(&a[3], &a[0]); +#elif defined test_bcheck_126 + strchr(&b[0], 'a'); +#elif defined test_bcheck_127 + free(strdup(&b[0])); +#endif +} +/* ------------------------------------------------------- */ +#endif diff --git a/tests/tests2/112_backtrace.expect b/tests/tests2/112_backtrace.expect new file mode 100644 index 0000000..68986c6 --- /dev/null +++ b/tests/tests2/112_backtrace.expect @@ -0,0 +1,142 @@ +[test_backtrace_1] +* main +* f1() +* f2() +* f3() +112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access +112_backtrace.c:14: by f2 +112_backtrace.c:19: by f1 +112_backtrace.c:24: by main +[returns 255] + +[test_bcheck_1] +* main +* f1() +112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest +112_backtrace.c:43: by main +[returns 255] + +[test_tcc_backtrace_2] +* main +* f1() +112_backtrace.c:64: at f1: Hello from f1! +112_backtrace.c:70: by main +* f2() +* exit f2 +[returns 34] + +[test_tcc_backtrace_3] +* main +[returns 1] + +[test_bcheck_100] +112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest +[returns 255] + +[test_bcheck_101] +112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src +[returns 255] + +[test_bcheck_102] +112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy +[returns 255] + +[test_bcheck_103] +112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy +[returns 255] + +[test_bcheck_104] +112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s1 +[returns 255] + +[test_bcheck_105] +112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s2 +[returns 255] + +[test_bcheck_106] +112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest +[returns 255] + +[test_bcheck_107] +112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src +[returns 255] + +[test_bcheck_108] +112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset +[returns 255] + +[test_bcheck_109] +112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen +[returns 255] + +[test_bcheck_110] +112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest +[returns 255] + +[test_bcheck_111] +112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src +[returns 255] + +[test_bcheck_112] +112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy +[returns 255] + +[test_bcheck_113] +112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy +[returns 255] + +[test_bcheck_114] +112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest +[returns 255] + +[test_bcheck_115] +112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src +[returns 255] + +[test_bcheck_116] +112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy +[returns 255] + +[test_bcheck_117] +112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy +[returns 255] + +[test_bcheck_118] +112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1 +[returns 255] + +[test_bcheck_119] +112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2 +[returns 255] + +[test_bcheck_120] +112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1 +[returns 255] + +[test_bcheck_121] +112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2 +[returns 255] + +[test_bcheck_122] +112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest +[returns 255] + +[test_bcheck_123] +112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest +[returns 255] + +[test_bcheck_124] +112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat +[returns 255] + +[test_bcheck_125] +112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat +[returns 255] + +[test_bcheck_126] +112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr +[returns 255] + +[test_bcheck_127] +112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup +[returns 255] diff --git a/tests/tests2/113_btdll.c b/tests/tests2/113_btdll.c new file mode 100644 index 0000000..8ae8981 --- /dev/null +++ b/tests/tests2/113_btdll.c @@ -0,0 +1,43 @@ +int tcc_backtrace(const char*, ...); +#define hello() \ + tcc_backtrace("hello from %s() / %s:%d",__FUNCTION__,__FILE__,__LINE__) + +#ifndef _WIN32 +# define __declspec(n) +#endif + +#if DLL==1 +__declspec(dllexport) int f_1() +{ + hello(); + return 0; +} + + +#elif DLL==2 +__declspec(dllexport) int f_2() +{ + hello(); + return 0; +} + + +#else + +int f_1(); +int f_2(); +int f_main() +{ + hello(); + return 0; +} + +int main () +{ + f_1(); + f_2(); + f_main(); + return 0; +} + +#endif diff --git a/tests/tests2/113_btdll.expect b/tests/tests2/113_btdll.expect new file mode 100644 index 0000000..34de481 --- /dev/null +++ b/tests/tests2/113_btdll.expect @@ -0,0 +1,6 @@ +113_btdll.c:12: at f_1: hello from f_1() / 113_btdll.c:12 +113_btdll.c:37: by main +113_btdll.c:20: at f_2: hello from f_2() / 113_btdll.c:20 +113_btdll.c:38: by main +113_btdll.c:31: at f_main: hello from f_main() / 113_btdll.c:31 +113_btdll.c:39: by main diff --git a/tests/tests2/114_bound_signal.c b/tests/tests2/114_bound_signal.c new file mode 100644 index 0000000..d7d7feb --- /dev/null +++ b/tests/tests2/114_bound_signal.c @@ -0,0 +1,110 @@ +#include <stdio.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <setjmp.h> + +/* See tcc-doc.info */ +#if defined(__TINYC__) && __BOUNDS_CHECKING_ON +#undef __attribute__ +extern void __bound_checking (int no_check); +#define BOUNDS_CHECKING_OFF __bound_checking(1) +#define BOUNDS_CHECKING_ON __bound_checking(-1) +#define BOUNDS_NO_CHECKING __attribute__((bound_no_checking)) +#else +#define BOUNDS_CHECKING_OFF +#define BOUNDS_CHECKING_ON +#define BOUNDS_NO_CHECKING +#endif + +static volatile int run = 1; +static int dummy[10]; +static sem_t sem; + +static void +add (void) BOUNDS_NO_CHECKING +{ + int i; + + for (i = 0; i < (sizeof(dummy)/sizeof(dummy[0])); i++) { + dummy[i]++; + } + /* Should not be translated into __bound_memset */ + memset (&dummy[0], 0, sizeof(dummy)); +} + +static void * +high_load (void *unused) +{ + while (run) { + add(); + } + return NULL; +} + +static void * +do_signal (void *unused) +{ + while (run) { + kill (getpid(), SIGUSR1); + while (sem_wait(&sem) < 0 && errno == EINTR); + } + return NULL; +} + +static void signal_handler(int sig) BOUNDS_NO_CHECKING +{ + add(); + sem_post (&sem); +} + +int +main (void) +{ + int i; + pthread_t id1, id2; + struct sigaction act; + sigjmp_buf sj; + sigset_t m; + time_t end; + + memset (&act, 0, sizeof (act)); + act.sa_handler = signal_handler; + act.sa_flags = 0; + sigemptyset (&act.sa_mask); + sigaction (SIGUSR1, &act, NULL); + + sem_init (&sem, 1, 0); + pthread_create(&id1, NULL, high_load, NULL); + pthread_create(&id2, NULL, do_signal, NULL); + + printf ("start\n"); + /* sleep does not work !!! */ + end = time(NULL) + 2; + while (time(NULL) < end) ; + run = 0; + printf ("end\n"); + + pthread_join(id1, NULL); + pthread_join(id2, NULL); + sem_destroy (&sem); + + sigemptyset (&m); + sigprocmask (SIG_SETMASK, &m, NULL); + if (sigsetjmp (sj, 0) == 0) + { + sigaddset (&m, SIGUSR1); + sigprocmask (SIG_SETMASK, &m, NULL); + siglongjmp (sj, 1); + printf ("failed"); + return 1; + } + sigprocmask (SIG_SETMASK, NULL, &m); + if (!sigismember (&m, SIGUSR1)) + printf ("failed"); + return 0; +} diff --git a/tests/tests2/114_bound_signal.expect b/tests/tests2/114_bound_signal.expect new file mode 100644 index 0000000..5d0fb3b --- /dev/null +++ b/tests/tests2/114_bound_signal.expect @@ -0,0 +1,2 @@ +start +end diff --git a/tests/tests2/115_bound_setjmp.c b/tests/tests2/115_bound_setjmp.c new file mode 100644 index 0000000..c402144 --- /dev/null +++ b/tests/tests2/115_bound_setjmp.c @@ -0,0 +1,169 @@ +#include <stdio.h> +#include <string.h> +#include <setjmp.h> + +#define TST int i, a[2], b[2]; \ + for (i = 0; i < 2; i++) a[i] = 0; \ + for (i = 0; i < 2; i++) b[i] = 0 + +static jmp_buf jmp; + +static void tst1 (void) +{ + TST; + longjmp(jmp, 1); +} + +static void tst2(void) +{ + jmp_buf jmp; + + setjmp (jmp); + TST; + tst1(); +} + +static void tst3 (jmp_buf loc) +{ + TST; + longjmp(loc, 1); +} + +static void tst4(jmp_buf loc) +{ + jmp_buf jmp; + + setjmp (jmp); + TST; + tst3(loc); +} + +static void tst (void) +{ + jmp_buf loc; + static int cnt; + + cnt = 0; + if (setjmp (jmp) == 0) { + TST; + tst2(); + } + else { + cnt++; + } + if (setjmp (loc) == 0) { + TST; + tst4(loc); + } + else { + cnt++; + } + if (cnt != 2) + printf ("incorrect cnt %d\n", cnt); +} + +static jmp_buf buf1; +static jmp_buf buf2; +static int *p; +static int n_x = 6; +static int g_counter; + +static void stack (void) +{ + static int counter; + static int way_point1; + static int way_point2; + + counter = 0; + way_point1 = 3; + way_point2 = 2; + g_counter = 0; + if (setjmp (buf1) != 101) { + int a[n_x]; + g_counter++; + p = &a[0]; + if (g_counter < 5) + longjmp (buf1, 2); + else if (g_counter == 5) + longjmp (buf1, 101); + else { + setjmp (buf2); + longjmp (buf1, 101); + } + } + + way_point1--; + + if (counter == 0) { + counter++; + { + int a[n_x]; + g_counter++; + p = &a[0]; + if (g_counter < 5) + longjmp (buf1, 2); + else if (g_counter == 5) + longjmp (buf1, 101); + else { + setjmp (buf2); + longjmp (buf1, 101); + } + } + } + + way_point2--; + + if (counter == 1) { + counter++; + longjmp (buf2, 2); + } + + if (!(way_point1 == 0 && way_point2 == 0 && + g_counter == 6 && counter == 2)) + printf ("Failed %d %d %d %d\n", + way_point1, way_point2, g_counter, counter); +} + +static jmp_buf env; +static int last_value; + +static void jump (int val) +{ + longjmp (env, val); +} + +static void check (void) +{ + int value; + + last_value = -1; + value = setjmp (env); + if (value != last_value + 1) { + printf ("incorrect value %d %d\n", + value, last_value + 1); + return; + } + last_value = value; + switch (value) { + case 0: + jump (0); + default: + if (value < 10) + jump (value + 1); + } +} + +int +main (void) +{ + int i; + + for (i = 0; i < 10; i++) { + tst(); + stack(); + check(); + } + return 0; +} + + diff --git a/tests/tests2/115_bound_setjmp.expect b/tests/tests2/115_bound_setjmp.expect new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/tests2/115_bound_setjmp.expect diff --git a/tests/tests2/116_bound_setjmp2.c b/tests/tests2/116_bound_setjmp2.c new file mode 100644 index 0000000..151114d --- /dev/null +++ b/tests/tests2/116_bound_setjmp2.c @@ -0,0 +1,84 @@ +#include <stdio.h> +#include <string.h> +#include <setjmp.h> +#if !defined(_WIN32) +#include <pthread.h> +#else +#include <windows.h> +#endif + +#define SIZE 10 +#define COUNT 10 + +#define TST int i, a[2], b[2]; \ + for (i = 0; i < 2; i++) a[i] = 0; \ + for (i = 0; i < 2; i++) b[i] = 0 + +static int count[SIZE]; + +static void tst1 (jmp_buf loc) +{ + TST; + longjmp(loc, 1); +} + +static void tst2(jmp_buf loc) +{ + jmp_buf jmp; + + setjmp (jmp); + TST; + tst1(loc); +} + +static void *tst (void * index) +{ + jmp_buf loc; + int i = *(int *) index; + static int v[SIZE]; + + for (v[i] = 0; v[i] < COUNT; v[i]++) { + if (setjmp (loc) == 0) { + TST; + tst2(loc); + } + else { + count[i]++; + } + i = *(int *) index; + } + return NULL; +} + +int +main (void) +{ + int i; +#if !defined(_WIN32) + pthread_t id[SIZE]; +#else + HANDLE id[SIZE]; +#endif + int index[SIZE]; + + for (i = 0; i < SIZE; i++) { + index[i] = i; +#if !defined(_WIN32) + pthread_create (&id[i], NULL, tst, (void *) &index[i]); +#else + id[i] = CreateThread(NULL, 8192, (LPTHREAD_START_ROUTINE) tst, (void *) &index[i], 0, NULL); +#endif + } + for (i = 0; i < SIZE; i++) { +#if !defined(_WIN32) + pthread_join (id[i], NULL); +#else + WaitForSingleObject(id[i], INFINITE); +#endif + } + for (i = 0; i < SIZE; i++) { + if (count[i] != COUNT) + printf ("error: %d %d\n", i, count[i]); + } + return 0; +} diff --git a/tests/tests2/116_bound_setjmp2.expect b/tests/tests2/116_bound_setjmp2.expect new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/tests2/116_bound_setjmp2.expect diff --git a/tests/tests2/117_gcc_test.c b/tests/tests2/117_gcc_test.c new file mode 100644 index 0000000..aed62e2 --- /dev/null +++ b/tests/tests2/117_gcc_test.c @@ -0,0 +1,158 @@ +#include <stdio.h> + +void tst_branch(void) +{ + goto *&&a; + printf ("dummy"); +a: ; +} + +void tst_void_ptr(void *pv, int i) +{ + i ? *pv : *pv; // dr106 +} + +void tst_shift(void) +{ + int i = 1; + long l = 1; + + i = i << 32; // illegal. just test + l = l << 64; // illegal. just test +} + +#if !defined(_WIN32) +#include <sys/mman.h> + +void tst_const_addr(void) +{ + void *addr = mmap ((void *)0x20000000, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS, -1, 0); + if (addr != (void *) -1) { +#if !defined(__riscv) + *(int *)0x20000000 += 42; +#endif + munmap (addr, 4096); + } +} +#endif + +struct zero_struct {}; + +struct zero_struct tst_zero_struct(void) +{ + struct zero_struct ret; + + return ret; +} + +struct big_struct { char a[262144]; }; + +struct big_struct tst_big(struct big_struct tst) +{ + return tst; +} + +void tst_adr (int (*fp)(char *, const char *, ...)) +{ + char buf[10]; + + (*fp)(buf, "%.0f", 5.0); +} + +static const char str[] = "abcdefghijklmnopqrstuvwxyz"; + +void tst_builtin(void) +{ + char *p; + char tmp[100]; + + if (__builtin_offsetof(struct big_struct, a) != 0) __builtin_abort(); + + p = __builtin_memcpy (tmp, str, sizeof(str)); + if (p != tmp) __builtin_abort(); + + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + p = __builtin_memmove(tmp, str, sizeof(str)); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + p = __builtin_memset(tmp, 0, sizeof (tmp)); + if (p != tmp || tmp[0] != 0 || tmp[99] != 0) __builtin_abort(); + + if (__builtin_strlen(str) != sizeof(str) - 1) __builtin_abort(); + + p = __builtin_strcpy(tmp, str); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + p = __builtin_strncpy(tmp, str, sizeof(str)); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + if (__builtin_strcmp (p, str)) __builtin_abort(); + + if (__builtin_strncmp (p, str, sizeof(str))) __builtin_abort(); + + tmp[0] = '\0'; + p = __builtin_strcat(tmp, str); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + + if (__builtin_strchr(p, 'z') != &p[25]) __builtin_abort(); + + p = __builtin_strdup (str); + if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort(); + __builtin_free(p); + + p = __builtin_malloc (100); + __builtin_memset(p, 0, 100); + p = __builtin_realloc (p, 1000); + __builtin_memset(p, 0, 1000); + __builtin_free(p); + + p = __builtin_calloc(10, 10); + __builtin_memset(p, 0, 100); + __builtin_free(p); + +#if defined(__i386__) || defined(__x86_64__) + p = __builtin_alloca(100); + __builtin_memset(p, 0, 100); +#endif +} + +int tst(void) +{ + long value = 3; + return -value; +} + +void tst_compare(void) +{ + /* This failed on risc64 */ + if (tst() > 0) printf ("error\n"); +} + +#pragma pack(1) +struct S { int d:24; int f:14; } i, j; +#pragma pack() + +void tst_pack (void) +{ + i.f = 5; j.f = 5; + if (j.f != i.f) printf("error\n"); +} + +int +main (void) +{ + struct big_struct big; + + tst_shift(); + tst_void_ptr(&big.a[0], 0); +#if !defined(_WIN32) + tst_const_addr(); +#endif + tst_zero_struct(); + tst_big(big); + tst_adr(&sprintf); + tst_builtin(); + tst_compare(); + tst_pack(); +} diff --git a/tests/tests2/117_gcc_test.expect b/tests/tests2/117_gcc_test.expect new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/tests2/117_gcc_test.expect diff --git a/tests/tests2/11_precedence.c b/tests/tests2/11_precedence.c index db2049d..845b6bf 100644 --- a/tests/tests2/11_precedence.c +++ b/tests/tests2/11_precedence.c @@ -1,4 +1,5 @@ -#include <stdio.h> +//#include <stdio.h> +extern int printf(const char *, ...); int main() { diff --git a/tests/tests2/22_floating_point.c b/tests/tests2/22_floating_point.c index e3491f5..2eb062c 100644 --- a/tests/tests2/22_floating_point.c +++ b/tests/tests2/22_floating_point.c @@ -1,6 +1,19 @@ #include <stdio.h> #include <math.h> +float fd; + +int +test() +{ + // was an internal tcc compiler error with arm64 backend until 2019-11-08 + if (fd < 5.5) { + return 1; + } else { + return 0; + } +} + int main() { // variables diff --git a/tests/tests2/33_ternary_op.c b/tests/tests2/33_ternary_op.c index 8579b50..1e6b56d 100644 --- a/tests/tests2/33_ternary_op.c +++ b/tests/tests2/33_ternary_op.c @@ -1,4 +1,43 @@ -#include <stdio.h> +#include <assert.h> +extern int printf(const char*, ...); + +char arr[1]; +static void f (void){} +void (*fp)(void) = f; +void call_fp() +{ + (fp?f:f)(); + (fp?fp:fp)(); + (fp?fp:&f)(); + (fp?&f:fp)(); + (fp?&f:&f)(); + _Generic(0?arr:arr, char*: (void)0); + _Generic(0?&arr[0]:arr, char*: (void)0); + _Generic(0?arr:&arr[0], char*: (void)0); + _Generic(1?arr:arr, char*: (void)0); + _Generic(1?&arr[0]:arr, char*: (void)0); + _Generic(1?arr:&arr[0], char*: (void)0); + _Generic((__typeof(1?f:f)*){0}, void (**)(void): (void)0); + (fp?&f:f)(); + (fp?f:&f)(); + _Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0); + + /* The following line causes a warning */ + void *xx = fp?f:1; +} + +struct condstruct { + int i; +}; + +static int getme(struct condstruct* s, int i) +{ + int i1 = (i != 0 ? 0 : s)->i; + int i2 = (i == 0 ? s : 0)->i; + int i3 = (i != 0 ? (void*)0 : s)->i; + int i4 = (i == 0 ? s : (void*)0)->i; + return i1 + i2 + i3 + i4; +} int main() { @@ -9,6 +48,32 @@ int main() printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3)); } + { + int c = 0; + #define ASSERT(X) assert(X) + static struct stru { int x; } a={'A'},b={'B'}; + static const struct stru2 { int x; } d = { 'D' }; + ASSERT('A'==(*(1?&a:&b)).x); + ASSERT('A'==(1?a:b).x); + ASSERT('A'==(c?b:a).x); + ASSERT('A'==(0?b:a).x); + c=1; + ASSERT('A'==(c?a:b).x); + ASSERT(sizeof(int) == sizeof(0 ? 'a' : c)); + ASSERT(sizeof(double) == sizeof(0 ? 'a' : 1.0)); + ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 'a')); + ASSERT(sizeof(float) == sizeof(0 ? 'a' : 1.0f)); + ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 1.0f)); + struct condstruct cs = { 38 }; + printf("%d\n", getme(&cs, 0)); + + // the following lines contain type mismatch errors in every ternary expression + //printf("comparing double with pointer : size = %d\n", sizeof(0 ? &c : 0.0)); + //printf("'%c' <> '%c'\n", (0 ? a : d).x, (1 ? a : d).x); + //0 ? a : 0.0; + } + + return 0; } diff --git a/tests/tests2/33_ternary_op.expect b/tests/tests2/33_ternary_op.expect index 45ea507..497be0e 100644 --- a/tests/tests2/33_ternary_op.expect +++ b/tests/tests2/33_ternary_op.expect @@ -1,3 +1,4 @@ +33_ternary_op.c:26: warning: pointer/integer mismatch in conditional expression 0 1 4 @@ -8,3 +9,4 @@ 21 24 27 +152 diff --git a/tests/tests2/46_grep.c b/tests/tests2/46_grep.c index 049dfb1..acda793 100644 --- a/tests/tests2/46_grep.c +++ b/tests/tests2/46_grep.c @@ -456,11 +456,13 @@ char *pmatch(char *line, char *pattern) while (*l && (e = pmatch(l, p))) l = e; /* Get longest match */ while (*p++ != ENDPAT); /* Skip over pattern */ - while (l >= are) { /* Try to match rest */ + while (l > are) { /* Try to match rest */ if (e = pmatch(l, p)) return(e); --l; /* Nope, try earlier */ } + if (e = pmatch(l, p)) + return(e); return(0); /* Nothing else worked */ default: diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index 0028caf..fd4367a 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -48,4 +48,302 @@ enum rgb3 c = 42; #elif defined test_74_non_const_init int i = i++; +#elif defined test_pointer_assignment + +void (*f1)(void); +void f2(void) {} + +struct s1 *ps1; +struct s2 *ps2; + +void *v1, **v2, ***v3; + +enum e1 { a = 4 } e10, *e11, *e12; +enum e2 { b = -4 } e20, *e21; +enum e3 { c = 5000000000LL } e30; + +int *ip; +unsigned int *up; +long *lp; +long long *llp; + +char **c1; +char const **c2; +unsigned char **u1; + +int no_main () +{ + // function + f1 = f2; + // struct + ps1 = ps2; + // void* + v1 = v3; + v2 = v3; + + // enum + e11 = e12; + e11 = e21; + e11 = &e10; + ip = &e10; + ip = &e20; + up = &e10; + up = &e20; + up = &e30; + + lp = ip; + lp = llp; + + // constness + c1 = c2; + *c1 = *c2; + **c1 = **c2; + + // unsigned = signed + u1 = c2; + *u1 = *c2; + **u1 = **c2; + + c2 = c1; + *c2 = *c1; + **c2 = **c1; + + return 0; +} + + +#elif defined test_enum_compat +enum e4; +enum e5; +void f3(enum e4 e); +void f3(enum e5 e); + +#elif defined test_enum_compat_2 +enum e6 { E1 = -1, E0 }; +void f3(enum e6); +void f3(int); // should work as int and e6 are compatible +void f4(enum e6 e); +void f4(unsigned e); // should error as unsigned and e6 are incompatible + +#elif defined test_ptr_to_str +void f() { _Generic((int const *[]){0}, int:0); } +#elif defined test_fnptr_to_str +void f() { _Generic((int (*(*)(float,char))(double,int)){0}, int:0); } +#elif defined test_array_to_str +void f() { _Generic((int(*)[3]){0}, int:0); } +#elif defined test_duplicate_def_1 +static enum myenum { L = -1 } L; +#elif defined test_duplicate_def_2 +void foo(void) { +static enum myenum { L = -1 } L; +} +#elif defined test_abstract_decls +int bar(const char *()); // abstract declarator here is okay +int bar (const char *(*g)()) // should match this 'g' argument +{ + g(); + return 42; +} +int foo(int ()) // abstract decl is wrong in definitions +{ + return 0; +#elif defined test_invalid_1 +void f(char*); +void g(void) { + f((char[]){1, ,}); +} +#elif defined test_invalid_2 +int ga = 0.42 { 2 }; +#elif defined test_invalid_3 +struct S { int a, b; }; +struct T { struct S x; }; +struct T gt = { 42 a: 1, 43 }; +#elif defined test_invalid_4 +enum E { + x = 1 / 0 +}; +#elif defined test_conflicting_types +int i; +void foo(void) { + int i; + { + extern double i; + i = 42.2; + } +} +#elif defined test_nested_types +union u { + union u { + int i; + } m; +}; +#elif defined test_vla_1 +int X=1; + +int main(void) { + int t[][][X]; +} +#elif defined test_invalid_alignas +/* _Alignas is no type qualifier */ +void * _Alignas(16) p1; + +#elif defined test_static_assert + +#define ONE 0 + _Static_assert(ONE == 0, "don't show me this"); + _Static_assert(ONE == 1, "ONE is not 1"); + +#elif defined test_static_assert_2 + _Static_assert(1, "1"" is 1"); + _Static_assert(0, "0"" is 0"); + +#elif defined test_static_assert_c2x + _Static_assert(1); + _Static_assert(0); + +#elif defined test_void_array + void t[3]; + +#elif defined test_incomplete_enum_array + enum e t[3]; + +#elif defined test_incomplete_struct_array + struct s t[3]; + +#elif defined test_const_fun_array + typedef void f(void); + const f t[3]; + +#elif defined test_incomplete_array_array + int t[][3]; // gr: not an error, see below + +/******************************************************************/ +#elif defined test_extern_array +int iii[] = { 1,2,3 }; +extern int iii[]; +int x[]; +int x[2]; +int x[]; +int x[2]; +int x[]; +extern int x[2]; +extern int x[]; +int x[3]; + +/******************************************************************/ +#elif defined test_func_1 \ + || defined test_func_2 \ + || defined test_func_3 \ + || defined test_func_4 \ + || defined test_func_5 \ + || defined test_func_6 +#if defined test_func_1 +int hello(int); +#elif defined test_func_4 +static int hello(int); +#endif +int main () { +#if defined test_func_6 + static +#endif + int hello(int); + hello(123); + return 0; +} +int printf(const char*, ...); +#if defined test_func_3 +static int hello(int a) +#elif defined test_func_5 +int hello(int a, int b) +#else +int hello(int a) +#endif +{ printf("%s: a = %d\n", __FUNCTION__, a); return 0; } + +/******************************************************************/ +#elif defined test_var_1 \ + || defined test_var_2 \ + || defined test_var_3 +#define P(n,v) printf("%-5s: %d ; %d\n", __FUNCTION__, n, v) +#if defined test_var_1 +int xxx[]; +#endif +int bar(); +int printf(const char*, ...); +int main () +{ +#if !defined test_var_3 + int xxx = 2; +#endif + { + extern int xxx[ +#if defined test_var_3 + 2 +#endif + ]; + P(1, xxx[0]); + xxx[0] += 2; + } +#if !defined test_var_3 + P(2, xxx); +#endif + bar(123); + return 0; +} +int xxx[1] = {1}; +int bar() { P(3, xxx[0]); return 0; } + +#elif defined test_var_4 +struct yyy { int y; }; +struct zzz; +void f1() { + extern char *x; + extern char **xx; + extern struct yyy y; + extern struct yyy *yy; + extern struct zzz z; + extern struct zzz *zz; +} +void f2() { + extern char *x; + extern char **xx; + extern struct yyy y; + extern struct yyy *yy; + extern struct zzz z; + extern struct zzz *zz; +} +struct yyy y, *yy; +struct zzz { int z; } z, *zz; + +/******************************************************************/ +#elif defined test_long_double_type_for_win32 + +int main() +{ + double *a = 0; + long double *b = a; + int n = _Generic(*a, double:0, long double:1); +} + +#elif defined test_stray_backslash +#define x \a +x + +#elif defined test_stray_backslash2 +int printf(const char*, ...); +int main() +{ +#define _S(x) #x +#define S(x) _S(x) + printf("%sn\n", S(\\)); +} + +/******************************************************************/ +#elif defined test_var_array + +static struct var_len { int i; const char str[]; } var_array[] = +{ { 1, "abcdefghijklmnopqrstuvwxyz" }, + { 2, "longlonglonglonglong" }, + { 3, "tst3" } }; + #endif diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index ed6a690..984e4c1 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -20,9 +20,145 @@ 60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED' [test_63_local_enumerator_redefinition] +[returns 1] [test_61_undefined_enum] 60_errors_and_warnings.c:46: error: unknown type size [test_74_non_const_init] 60_errors_and_warnings.c:49: error: initializer element is not constant + +[test_pointer_assignment] +60_errors_and_warnings.c:79: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:82: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:86: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:88: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:91: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:92: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:94: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:95: warning: assignment from incompatible pointer type +60_errors_and_warnings.c:98: warning: assignment discards qualifiers from pointer target type +60_errors_and_warnings.c:99: warning: assignment discards qualifiers from pointer target type +60_errors_and_warnings.c:103: warning: assignment discards qualifiers from pointer target type +60_errors_and_warnings.c:104: warning: assignment discards qualifiers from pointer target type +60_errors_and_warnings.c:109: warning: assignment of read-only location + +[test_enum_compat] +60_errors_and_warnings.c:119: error: incompatible types for redefinition of 'f3' + +[test_enum_compat_2] +60_errors_and_warnings.c:126: error: incompatible types for redefinition of 'f4' + +[test_ptr_to_str] +60_errors_and_warnings.c:129: error: type 'const int **' does not match any association + +[test_fnptr_to_str] +60_errors_and_warnings.c:131: error: type 'int (*(*)(float, char))(double, int)' does not match any association + +[test_array_to_str] +60_errors_and_warnings.c:133: error: type 'int (*)[3]' does not match any association + +[test_duplicate_def_1] +60_errors_and_warnings.c:135: error: redefinition of 'L' + +[test_duplicate_def_2] +60_errors_and_warnings.c:138: error: redeclaration of 'L' + +[test_abstract_decls] +60_errors_and_warnings.c:148: error: identifier expected + +[test_invalid_1] +60_errors_and_warnings.c:153: error: identifier expected + +[test_invalid_2] +60_errors_and_warnings.c:156: error: ';' expected (got "{") + +[test_invalid_3] +60_errors_and_warnings.c:160: error: ',' expected (got "a") + +[test_invalid_4] +60_errors_and_warnings.c:164: error: division by zero in constant + +[test_conflicting_types] +60_errors_and_warnings.c:170: error: incompatible types for redefinition of 'i' + +[test_nested_types] +60_errors_and_warnings.c:177: error: struct/union/enum already defined + +[test_vla_1] +60_errors_and_warnings.c:184: error: need explicit inner array size in VLAs + +[test_invalid_alignas] +60_errors_and_warnings.c:188: error: identifier expected + +[test_static_assert] +60_errors_and_warnings.c:194: error: ONE is not 1 + +[test_static_assert_2] +60_errors_and_warnings.c:198: error: 0 is 0 + +[test_static_assert_c2x] +60_errors_and_warnings.c:202: error: _Static_assert fail + +[test_void_array] +60_errors_and_warnings.c:205: error: declaration of an array of incomplete type elements + +[test_incomplete_enum_array] +60_errors_and_warnings.c:208: error: declaration of an array of incomplete type elements + +[test_incomplete_struct_array] +60_errors_and_warnings.c:211: error: declaration of an array of incomplete type elements + +[test_const_fun_array] +60_errors_and_warnings.c:215: error: declaration of an array of functions + +[test_incomplete_array_array] + +[test_extern_array] +60_errors_and_warnings.c:231: error: incompatible types for redefinition of 'x' + +[test_func_1] +hello: a = 123 + +[test_func_2] +hello: a = 123 + +[test_func_3] +60_errors_and_warnings.c:261: warning: static storage ignored for redefinition of 'hello' +hello: a = 123 + +[test_func_4] +hello: a = 123 + +[test_func_5] +60_errors_and_warnings.c:261: error: incompatible types for redefinition of 'hello' + +[test_func_6] +60_errors_and_warnings.c:249: error: function without file scope cannot be static + +[test_var_1] +main : 1 ; 1 +main : 2 ; 2 +bar : 3 ; 3 + +[test_var_2] +main : 1 ; 1 +main : 2 ; 2 +bar : 3 ; 3 + +[test_var_3] +60_errors_and_warnings.c:293: error: incompatible types for redefinition of 'xxx' + +[test_var_4] + +[test_long_double_type_for_win32] +60_errors_and_warnings.c:324: warning: assignment from incompatible pointer type + +[test_stray_backslash] +60_errors_and_warnings.c:330: error: stray '\' in program + +[test_stray_backslash2] +\n + +[test_var_array] +60_errors_and_warnings.c:345: warning: initializer-string for array is too long diff --git a/tests/tests2/61_integers.c b/tests/tests2/61_integers.c new file mode 100644 index 0000000..de29b3c --- /dev/null +++ b/tests/tests2/61_integers.c @@ -0,0 +1,70 @@ +#include <stdio.h> + +/* This was first introduced to test the ARM port */ + +#define UINT_MAX ((unsigned) -1) + +int main() +{ + printf("18/21=%u\n", 18/21); + printf("18%%21=%u\n", 18%21); + printf("41/21=%u\n", 41/21); + printf("41%%21=%u\n", 41%21); + printf("42/21=%u\n", 42/21); + printf("42%%21=%u\n", 42%21); + printf("43/21=%u\n", 43/21); + printf("43%%21=%u\n", 43%21); + printf("126/21=%u\n", 126/21); + printf("126%%21=%u\n", 126%21); + printf("131/21=%u\n", 131/21); + printf("131%%21=%u\n", 131%21); + printf("(UINT_MAX/2+3)/2=%u\n", (UINT_MAX/2+3)/2); + printf("(UINT_MAX/2+3)%%2=%u\n", (UINT_MAX/2+3)%2); + + printf("18/-21=%u\n", 18/-21); + printf("18%%-21=%u\n", 18%-21); + printf("41/-21=%u\n", 41/-21); + printf("41%%-21=%u\n", 41%-21); + printf("42/-21=%u\n", 42/-21); + printf("42%%-21=%u\n", 42%-21); + printf("43/-21=%u\n", 43/-21); + printf("43%%-21=%u\n", 43%-21); + printf("126/-21=%u\n", 126/-21); + printf("126%%-21=%u\n", 126%-21); + printf("131/-21=%u\n", 131/-21); + printf("131%%-21=%u\n", 131%-21); + printf("(UINT_MAX/2+3)/-2=%u\n", (UINT_MAX/2+3)/-2); + printf("(UINT_MAX/2+3)%%-2=%u\n", (UINT_MAX/2+3)%-2); + + printf("-18/21=%u\n", -18/21); + printf("-18%%21=%u\n", -18%21); + printf("-41/21=%u\n", -41/21); + printf("-41%%21=%u\n", -41%21); + printf("-42/21=%u\n", -42/21); + printf("-42%%21=%u\n", -42%21); + printf("-43/21=%u\n", -43/21); + printf("-43%%21=%u\n", -43%21); + printf("-126/21=%u\n", -126/21); + printf("-126%%21=%u\n", -126%21); + printf("-131/21=%u\n", -131/21); + printf("-131%%21=%u\n", -131%21); + printf("-(UINT_MAX/2+3)/2=%u\n", (0-(UINT_MAX/2+3))/2); + printf("-(UINT_MAX/2+3)%%2=%u\n", (0-(UINT_MAX/2+3))%2); + + printf("-18/-21=%u\n", -18/-21); + printf("-18%%-21=%u\n", -18%-21); + printf("-41/-21=%u\n", -41/-21); + printf("-41%%-21=%u\n", -41%-21); + printf("-42/-21=%u\n", -42/-21); + printf("-42%%-21=%u\n", -42%-21); + printf("-43/-21=%u\n", -43/-21); + printf("-43%%-21=%u\n", -43%-21); + printf("-126/-21=%u\n", -126/-21); + printf("-126%%-21=%u\n", -126%-21); + printf("-131/-21=%u\n", -131/-21); + printf("-131%%-21=%u\n", -131%-21); + printf("-(UINT_MAX/2+3)/-2=%u\n", (0-(UINT_MAX/2+3))/-2); + printf("-(UINT_MAX/2+3)%%-2=%u\n", (0-(UINT_MAX/2+3))%-2); + + return 0; +} diff --git a/tests/tests2/61_integers.expect b/tests/tests2/61_integers.expect new file mode 100644 index 0000000..22c8d1b --- /dev/null +++ b/tests/tests2/61_integers.expect @@ -0,0 +1,56 @@ +18/21=0 +18%21=18 +41/21=1 +41%21=20 +42/21=2 +42%21=0 +43/21=2 +43%21=1 +126/21=6 +126%21=0 +131/21=6 +131%21=5 +(UINT_MAX/2+3)/2=1073741825 +(UINT_MAX/2+3)%2=0 +18/-21=0 +18%-21=18 +41/-21=4294967295 +41%-21=20 +42/-21=4294967294 +42%-21=0 +43/-21=4294967294 +43%-21=1 +126/-21=4294967290 +126%-21=0 +131/-21=4294967290 +131%-21=5 +(UINT_MAX/2+3)/-2=0 +(UINT_MAX/2+3)%-2=2147483650 +-18/21=0 +-18%21=4294967278 +-41/21=4294967295 +-41%21=4294967276 +-42/21=4294967294 +-42%21=0 +-43/21=4294967294 +-43%21=4294967295 +-126/21=4294967290 +-126%21=0 +-131/21=4294967290 +-131%21=4294967291 +-(UINT_MAX/2+3)/2=1073741823 +-(UINT_MAX/2+3)%2=0 +-18/-21=0 +-18%-21=4294967278 +-41/-21=1 +-41%-21=4294967276 +-42/-21=2 +-42%-21=0 +-43/-21=2 +-43%-21=4294967295 +-126/-21=6 +-126%-21=0 +-131/-21=6 +-131%-21=4294967291 +-(UINT_MAX/2+3)/-2=0 +-(UINT_MAX/2+3)%-2=2147483646 diff --git a/tests/tests2/73_arm64.c b/tests/tests2/73_arm64.c index 8de61b3..855c476 100644 --- a/tests/tests2/73_arm64.c +++ b/tests/tests2/73_arm64.c @@ -230,6 +230,17 @@ void ret(void) printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d); } +void* +va_arg_with_struct_ptr(va_list ap) { + /* + * This was a BUG identified with FFTW-3.3.8 on arm64. + * The test case only checks it compiles. + */ + struct X { int _x; }; + struct X *x = va_arg(ap, struct X *); + return x; +} + int match(const char **s, const char *f) { const char *p = *s; diff --git a/tests/tests2/81_types.c b/tests/tests2/81_types.c index fd6d71b..0bc3bae 100644 --- a/tests/tests2/81_types.c +++ b/tests/tests2/81_types.c @@ -39,5 +39,17 @@ int f5 (fptr5 fp, fptr1 i) { return fp(i); } +typedef int intx4[4]; +int f8 (intx4, int); int f8 (int ([4]), int); +int f8 (int y[4], int i) +{ + return y[i]; +} +int f9 (int (*)(int), int); +int f9 (int ((int)), int); +int f9 (int f(int), int i) +{ + return f(i); +} int main () { return 0; } diff --git a/tests/tests2/82_attribs_position.c b/tests/tests2/82_attribs_position.c index 7c9f987..fd3f2c4 100644 --- a/tests/tests2/82_attribs_position.c +++ b/tests/tests2/82_attribs_position.c @@ -16,4 +16,50 @@ void __attribute__((stdcall)) foo (void) { } -int main () { return 0; } +#define __stdcall __attribute__((stdcall)) +extern int some_stdcall_func (int, int, int) __stdcall; +__stdcall int __stdcall some_stdcall_func(int foo, int bar, int baz) { + //printf("Hello from stdcall: %i %i %i\n", foo, bar, baz); + return 43; +} + +/* The actual attribute isn't important, must just be + parsable. */ +#define ATTR __attribute__((__noinline__)) +int ATTR actual_function() { + return 42; +} + +extern int printf (const char *, ...); +static int globalvar; +int main() +{ + void *function_pointer = &actual_function; + int localvar = 42, i; + + int a = ((ATTR int(*) (void)) function_pointer)(); + printf("%i\n", a); + + /* In the following we once misparsed 'ATTR *' is a btype + and hence the whole type was garbled. */ + int b = ( (int(ATTR *)(void)) function_pointer)(); + printf("%i\n", b); + + /* All these should work and leave the stack pointer in its original + position. */ + some_stdcall_func(1, 10, 100); + ((int __stdcall (*)(int, int, int))some_stdcall_func) (2, 20, 200); + ((int(*__stdcall)(int, int, int))some_stdcall_func) (3, 30, 300); + for (i = 0; i < 1024; i++) { + globalvar = i; + /* This was once misparsed at <= gitrev 325241c0, forgetting + the stdcall attribute on the function pointer leading to + stack increment being done twice (in callee and caller). + This will clobber 'i' and 'localvar' which is how we detect + this. */ + ((int(__stdcall*)(int, int, int))some_stdcall_func) (4, 40, 400); + if (localvar != 42 || globalvar != i) + printf("error, localvar=%d i=%d globalvar=%d\n", localvar, i, globalvar); + } + return 0; +} diff --git a/tests/tests2/82_attribs_position.expect b/tests/tests2/82_attribs_position.expect index e69de29..daaac9e 100644 --- a/tests/tests2/82_attribs_position.expect +++ b/tests/tests2/82_attribs_position.expect @@ -0,0 +1,2 @@ +42 +42 diff --git a/tests/tests2/85_asm-outside-function.c b/tests/tests2/85_asm-outside-function.c index dc5639a..3d7434d 100644 --- a/tests/tests2/85_asm-outside-function.c +++ b/tests/tests2/85_asm-outside-function.c @@ -1,6 +1,12 @@ +#ifdef __leading_underscore +# define _ "_" +#else +# define _ +#endif + extern int printf (const char *, ...); extern void vide(void); -__asm__("vide: ret"); +__asm__(_"vide: ret"); int main() { vide(); diff --git a/tests/tests2/87_dead_code.c b/tests/tests2/87_dead_code.c index 98d4566..0d5a64c 100644 --- a/tests/tests2/87_dead_code.c +++ b/tests/tests2/87_dead_code.c @@ -26,6 +26,36 @@ static void kb_wait_1(void) timeout--; } while (timeout); } + +static int global; + +static void foo(int i) +{ + global+=i; + printf ("g=%d\n", global); +} + +static int check(void) +{ + printf ("check %d\n", global); + return 1; +} + +static void dowhile(void) +{ + do { + foo(1); + if (global == 1) { + continue; + } else if (global == 2) { + continue; + } + /* The following break shouldn't disable the check() call, + as it's reachable by the continues above. */ + break; + } while (check()); +} + int main (void) { int i = 1; @@ -118,5 +148,8 @@ enterloop3: printf ("error4\n"); } } + + dowhile(); + return 0; } diff --git a/tests/tests2/87_dead_code.expect b/tests/tests2/87_dead_code.expect index 0b3ec1d..a8c93bd 100644 --- a/tests/tests2/87_dead_code.expect +++ b/tests/tests2/87_dead_code.expect @@ -16,3 +16,8 @@ once3 twice3 caseok caseok2 +g=1 +check 1 +g=2 +check 2 +g=3 diff --git a/tests/tests2/88_codeopt.c b/tests/tests2/88_codeopt.c index 647626f..2ab4c8a 100644 --- a/tests/tests2/88_codeopt.c +++ b/tests/tests2/88_codeopt.c @@ -1,7 +1,7 @@ /* Check some way in where code suppression caused various miscompilations. */ extern int printf (const char *, ...); -typedef unsigned long size_t; +typedef __SIZE_TYPE__ size_t; size_t _brk_start, _brk_end; void * extend_brk(size_t size, size_t align) @@ -51,6 +51,7 @@ _Bool chk(unsigned long addr, unsigned long limit, unsigned long size) only with certain internal checking added that's not committed). */ if (0) ret = 0 != (!!(addr > limit - size)); + return 0; } int main() diff --git a/tests/tests2/90_struct-init.c b/tests/tests2/90_struct-init.c index d931e23..ade7fad 100644 --- a/tests/tests2/90_struct-init.c +++ b/tests/tests2/90_struct-init.c @@ -87,6 +87,13 @@ union UV guv = {{6,5}}; union UV guv2 = {{.b = 7, .a = 8}}; union UV guv3 = {.b = 8, .a = 7}; +struct SSU { + int y; + struct { int x; }; +}; +struct SSU gssu1 = { .y = 5, .x = 3 }; +struct SSU gssu2 = { 5, 3 }; + /* Under -fms-extensions also the following is valid: union UV2 { struct Anon {u8 a,b;}; // unnamed member, but tagged struct, ... @@ -166,6 +173,14 @@ void foo (struct W *w, struct pkthdr *phdr_) int elt = 0x42; /* Range init, overlapping */ struct T lt2 = { { [1 ... 5] = 9, [6 ... 10] = elt, [4 ... 7] = elt+1 }, 1 }; + struct SSU lssu1 = { 5, 3 }; + struct SSU lssu2 = { .y = 5, .x = 3 }; + /* designated initializers in GNU form */ +#if defined(__GNUC__) || defined(__TINYC__) + struct S ls4 = {a: 1, b: 2, c: {3, 4}}; +#else + struct S ls4 = {.a = 1, .b = 2, .c = {3, 4}}; +#endif print(ls); print(ls2); print(lt); @@ -182,7 +197,10 @@ void foo (struct W *w, struct pkthdr *phdr_) print(lv2); print(lv3); print(lt2); + print(lssu1); + print(lssu2); print(flow); + print(ls4); } #endif @@ -272,6 +290,8 @@ int main() print(guv.b); print(guv2); print(guv3); + print(gssu1); + print(gssu2); print(phdr); foo(&gw, &phdr); //printf("q: %s\n", q); diff --git a/tests/tests2/90_struct-init.expect b/tests/tests2/90_struct-init.expect index e366121..c55cb47 100644 --- a/tests/tests2/90_struct-init.expect +++ b/tests/tests2/90_struct-init.expect @@ -17,6 +17,8 @@ guv: 6 5 0 0 guv.b: 5 guv2: 8 7 0 0 guv3: 7 8 0 0 +gssu1: 5 0 0 0 3 0 0 0 +gssu2: 5 0 0 0 3 0 0 0 phdr: 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 ls: 1 2 3 4 ls2: 1 2 3 4 @@ -34,7 +36,10 @@ lv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30 lv3: 7 8 9 a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 lt2: 0 9 9 9 43 43 43 43 42 42 42 0 0 0 0 0 1 +lssu1: 5 0 0 0 3 0 0 0 +lssu2: 5 0 0 0 3 0 0 0 flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 +ls4: 1 2 3 4 one two three diff --git a/tests/tests2/92_enum_bitfield.c b/tests/tests2/92_enum_bitfield.c index bb6dc35..fb8f7a3 100644 --- a/tests/tests2/92_enum_bitfield.c +++ b/tests/tests2/92_enum_bitfield.c @@ -45,6 +45,7 @@ int convert_like_real (tree convs) break; }; printf("unsigned enum bit-fields broken\n"); + return 0; } int main() diff --git a/tests/tests2/94_generic.c b/tests/tests2/94_generic.c index d7fb5fc..6e85c02 100644 --- a/tests/tests2/94_generic.c +++ b/tests/tests2/94_generic.c @@ -20,6 +20,12 @@ int b_f() return 10; } +typedef int (*fptr)(int); +int foo(int i) +{ + return i; +} + typedef int int_type1; #define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123); @@ -60,5 +66,50 @@ int main() long long: "long long")); i = _Generic(l, long: 1, int: 2); printf("%d\n", i); + i = _Generic(foo, fptr: 3, int: 4); + printf("%d\n", i); + + (void)_Generic((int(*)[2]){0}, int(*)[2]:0, int(*)[4]:0); //shouldn't match twice + + //should accept ({ }) in the controlling expr of _Generic even in const_wanted contexts + struct { _Bool x_0: _Generic(({0;}),default:1); } my_x; + + _Generic((__typeof((float const)((float const){42}))*){0}, float*: 0); //casts lose top-level qualifiers + int const x = 42; __typeof((__typeof(x))x) *xp = 0; (void)_Generic(xp, int*: 0); //casts lose top-level qualifiers + + //TEST TERNARY: + //Same type + _Generic( 0?(long*)0:(long*)0, long*: (void)0); + //combining of qualifiers + _Generic( 0?(long volatile*)0:(long const*)0, long const volatile*: (void)0); + //nul-ptr constant selects other type + _Generic( 0?(long*)0:0, long*: (void)0); + _Generic( 0?(long*)0:(void*)0, long*: (void)0); + + //void ptrs get chosen preferentially; qualifs still combine + _Generic( 0?(int volatile*)0: (void const*)1, void volatile const*: (void)0); + //like gcc but not clang, don't treat (void* const as the null-ptr constant) + _Generic( 0?(int volatile*)0: (void const*)0, void volatile const*: (void)0); + + //ptrs to incomplete types get completed + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + + { + /* completion shouldn't affect the type of decl */ + char **argv; + _Generic(argv, char**: (void)0); + _Generic(0?(char const*)0:argv[0], char const*: (void)0); + _Generic(argv, char**: (void)0); + } + { + extern int (*ar)[]; + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?ar : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : ar, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[5])0 : ar, int (*)[5]:+1, int (*)[4]:(void)0); })); + } + return 0; } diff --git a/tests/tests2/94_generic.expect b/tests/tests2/94_generic.expect index 9aa9275..748d78f 100644 --- a/tests/tests2/94_generic.expect +++ b/tests/tests2/94_generic.expect @@ -10,4 +10,5 @@ 3 4 long -1
\ No newline at end of file +1 +3 diff --git a/tests/tests2/95_bitfields.c b/tests/tests2/95_bitfields.c index f025c57..4ac38da 100644 --- a/tests/tests2/95_bitfields.c +++ b/tests/tests2/95_bitfields.c @@ -78,6 +78,27 @@ } /* ----------------------------------------------------------------------- */ +#elif TEST == 7 +{ +#ifdef _WIN32 + typedef long long int ll; +#else + typedef long int ll; +#endif + struct M P __s { + ll d : 16; + ll b : 16; + ll x : 16; + ll y : 1; + ll z : 2; + ll a : 11; + ll e : 1; + ll f : 1; + }; + TEST_STRUCT(1,2,3,4,5); +} + +/* ----------------------------------------------------------------------- */ #elif defined PACK #if PACK @@ -101,6 +122,8 @@ top = 0; #include SELF #define TEST 6 #include SELF +#define TEST 7 +#include SELF #if PACK # pragma pack(pop) diff --git a/tests/tests2/95_bitfields.expect b/tests/tests2/95_bitfields.expect index 6a8fd9a..215055d 100644 --- a/tests/tests2/95_bitfields.expect +++ b/tests/tests2/95_bitfields.expect @@ -34,6 +34,12 @@ bits as set : 00000030002001FD00000004 values : 01 02 03 04 fffffffd align/size : 4 12 +---- TEST 7 ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 01 00 ffffffff 04 05 +align/size : 8 8 + ---- TEST 1 - PACKED ---- @@ -72,6 +78,12 @@ bits as set : 0030002001FD00000004 values : 01 02 03 04 fffffffd align/size : 1 10 +---- TEST 7 - PACKED ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 01 00 ffffffff 04 05 +align/size : 1 8 + ---- TEST 1 - WITH ALIGN ---- @@ -110,6 +122,12 @@ bits as set : 00000030002001FD00000004 values : 01 02 03 04 fffffffd align/size : 4 12 +---- TEST 7 - WITH ALIGN ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 01 00 ffffffff 04 05 +align/size : 8 8 + ---- TEST 1 - PACKED - WITH ALIGN ---- @@ -147,3 +165,9 @@ bits in use : 007000FFFFFFFFFFFFFF bits as set : 0030002001FD00000004 values : 01 02 03 04 fffffffd align/size : 1 10 + +---- TEST 7 - PACKED - WITH ALIGN ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 01 00 ffffffff 04 05 +align/size : 1 8 diff --git a/tests/tests2/95_bitfields_ms.expect b/tests/tests2/95_bitfields_ms.expect index 8ccafb7..97c46be 100644 --- a/tests/tests2/95_bitfields_ms.expect +++ b/tests/tests2/95_bitfields_ms.expect @@ -34,6 +34,12 @@ bits as set : 000000000000003000002001000000FD00000004 values : 01 02 03 04 fffffffd align/size : 4 20 +---- TEST 7 - MS-BITFIELDS ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005 +align/size : 8 8 + ---- TEST 1 - MS-BITFIELDS - PACKED ---- @@ -72,6 +78,12 @@ bits as set : 000000003000002001FD00000004 values : 01 02 03 04 fffffffd align/size : 1 14 +---- TEST 7 - MS-BITFIELDS - PACKED ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005 +align/size : 1 8 + ---- TEST 1 - MS-BITFIELDS - WITH ALIGN ---- @@ -110,6 +122,12 @@ bits as set : 000000000000003000002001000000FD00000004 values : 01 02 03 04 fffffffd align/size : 4 20 +---- TEST 7 - MS-BITFIELDS - WITH ALIGN ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005 +align/size : 8 8 + ---- TEST 1 - MS-BITFIELDS - PACKED - WITH ALIGN ---- @@ -147,3 +165,9 @@ bits in use : 00000000700000FFFFFFFFFFFFFF bits as set : 000000003000002001FD00000004 values : 01 02 03 04 fffffffd align/size : 1 14 + +---- TEST 7 - MS-BITFIELDS - PACKED - WITH ALIGN ---- +bits in use : 3FFFFFFFFFFF0000 +bits as set : 0026000100050000 +values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005 +align/size : 1 8 diff --git a/tests/tests2/96_nodata_wanted.c b/tests/tests2/96_nodata_wanted.c index cc211d3..790b431 100644 --- a/tests/tests2/96_nodata_wanted.c +++ b/tests/tests2/96_nodata_wanted.c @@ -55,11 +55,10 @@ te0:; static char ds1 = 0; ts1:; if (!SKIP) { - static void *p = (void*)&main; - static char cc[] = "static string"; - static double d = 8.0; - - static struct __attribute__((packed)) { + void *p = (void*)&main; + char cc[] = "static string"; + double d = 8.0; + struct __attribute__((packed)) { unsigned x : 12; unsigned char y : 7; unsigned z : 28, a: 4, b: 5; @@ -81,4 +80,19 @@ te1:; /*printf("# %d/%d\n", dl, tl);*/ } +#elif defined test_static_data + +#include <stdio.h> +int main(int argc, char **argv) +{ + goto there; + if (0) { + static int a = 1; + printf("hello\n"); /* the "hello\n" string is still suppressed */ +there: + printf("a = %d\n", a); + } + return 0; +} + #endif diff --git a/tests/tests2/96_nodata_wanted.expect b/tests/tests2/96_nodata_wanted.expect index 2749109..92dc9c4 100644 --- a/tests/tests2/96_nodata_wanted.expect +++ b/tests/tests2/96_nodata_wanted.expect @@ -9,7 +9,7 @@ [test_local_data_noerror] 96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast -96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short +96_nodata_wanted.c:25: warning: cast between pointer and integer of different size [test_data_suppression_off] data: @@ -21,3 +21,6 @@ size of data/text: [test_data_suppression_on] size of data/text: zero/zero + +[test_static_data] +a = 1 diff --git a/tests/tests2/98_al_ax_extend.c b/tests/tests2/98_al_ax_extend.c index 9b4e02f..1cd6585 100644 --- a/tests/tests2/98_al_ax_extend.c +++ b/tests/tests2/98_al_ax_extend.c @@ -8,7 +8,7 @@ asm ( "ret;" ); -#if 1 +#ifndef __leading_underscore #define us _us #define ss _ss #define uc _uc diff --git a/tests/tests2/99_fastcall.c b/tests/tests2/99_fastcall.c index ee4b67d..8fbc904 100644 --- a/tests/tests2/99_fastcall.c +++ b/tests/tests2/99_fastcall.c @@ -5,7 +5,7 @@ #define __fastcall __attribute((fastcall)) #endif -#if 1 +#ifndef __leading_underscore #define SYMBOL(x) _##x #else #define SYMBOL(x) x diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index 190b2d9..8b169b4 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -3,7 +3,9 @@ include $(TOP)/Makefile SRC = $(TOPSRC)/tests/tests2 VPATH = $(SRC) -TESTS = $(patsubst %.c,%.test,$(sort $(notdir $(wildcard $(SRC)/*.c)))) +TESTS = $(patsubst %.c,%.test,\ + $(sort $(notdir $(wildcard $(SRC)/??_*.c)))\ + $(sort $(notdir $(wildcard $(SRC)/???_*.c)))) # some tests do not pass on all platforms, remove them for now SKIP = 34_array_assignment.test # array assignment is not in C standard @@ -12,7 +14,7 @@ ifeq ($(CONFIG_arm_eabi),yes) # not ARM soft-float endif ifdef CONFIG_OSX SKIP += 40_stdio.test 42_function_pointer.test - FLAGS += -w + SKIP += 113_btdll.test # no shared lib support yet endif ifeq ($(ARCH),x86_64) SKIP += 73_arm64.test @@ -21,7 +23,17 @@ ifeq (,$(filter i386,$(ARCH))) SKIP += 98_al_ax_extend.test 99_fastcall.test endif ifeq (,$(filter i386 x86_64,$(ARCH))) - SKIP += 85_asm-outside-function.test + SKIP += 85_asm-outside-function.test # x86 asm + SKIP += 113_btdll.test # dll support needed +endif +ifeq (,$(filter i386 x86_64 arm arm64 riscv64,$(ARCH))) + SKIP += 112_backtrace.test + SKIP += 114_bound_signal.test + SKIP += 115_bound_setjmp.test + SKIP += 116_bound_setjmp2.test +endif +ifeq (-$(CONFIG_musl)-,-yes-) + SKIP += 112_backtrace.test endif ifeq (-$(findstring gcc,$(CC))-,--) SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS)) @@ -29,6 +41,10 @@ endif ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-) SKIP += 95_bitfields%.test # type_align is different on 32bit-non-windows endif +ifeq (-$(CONFIG_WIN32)-,-yes-) + SKIP += 106_pthread.test # No pthread support + SKIP += 114_bound_signal.test # No pthread support +endif # Some tests might need arguments ARGS = @@ -54,21 +70,47 @@ GEN-ALWAYS = # using the ms compiler for the really ms-compatible bitfields 95_bitfields_ms.test : GEN = $(GEN-MSC) +# this test compiles/links two files: +104_inline.test : FLAGS += $(subst 104,104+,$1) +104_inline.test : GEN = $(GEN-TCC) + +# this test needs pthread +106_pthread.test: FLAGS += -pthread +106_pthread.test: NORUN = true + +# constructor/destructor +108_constructor.test: NORUN = true + +112_backtrace.test: FLAGS += -dt -b +112_backtrace.test 113_btdll.test: FILTER += \ + -e 's;[0-9A-Fa-fx]\{5,\};........;g' \ + -e 's;0x[0-9A-Fa-f]\{1,\};0x?;g' + +# this test creates two DLLs and an EXE +113_btdll.test: NORUN = true +113_btdll.test: FLAGS += \ + -bt $1 -shared -D DLL=1 -o a1$(DLLSUF) && $(TCC) \ + -bt $1 -shared -D DLL=2 -o a2$(DLLSUF) && $(TCC) \ + -bt a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. + +114_bound_signal.test: FLAGS += -b +115_bound_setjmp.test: FLAGS += -b +116_bound_setjmp2.test: FLAGS += -b + +117_gcc_test.test: FLAGS += $(T2) && $(TCC) -b + # Filter source directory in warnings/errors (out-of-tree builds) -FILTER = 2>&1 | sed 's,$(SRC)/,,g' -# Filter some always-warning -ifeq (-$(findstring arm,$(ARCH))-,-arm-) -FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported' -endif +FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' -all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ; +all test tests2.all: $(filter-out $(SKIP),$(TESTS)) + @$(MAKE) clean --no-print-directory -s %.test: %.c %.expect @echo Test: $*... - @$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3)) + @$(call T1,$<) $(T3) -T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS) -T2 = $(TCC) $(FLAGS) -run $< $(ARGS) +T1 = $(TCC) $(FLAGS) $(T2) $(ARGS) +T2 = $(if $(NORUN),$1 -o a.exe && ./a.exe,-run $1) T3 = $(FILTER) >$*.output 2>&1 || true \ && diff -Nbu $(filter %.expect,$^) $*.output \ && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS)) @@ -79,7 +121,7 @@ tests2.%+: # just run tcc to see the output, e.g. "make tests2.37-" tests2.%-: - @$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory + @$(MAKE) $(call F1,$*) T3= --no-print-directory # run single test, e.g. "make tests2.37" tests2.%: @@ -95,9 +137,9 @@ F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)" @rm -f *.exe *.obj *.pdb # using TCC for .expect if -dt in FLAGS -GEN = $(if $(filter -dt,$(FLAGS)),$(GEN-TCC),$(GEN-CC)) +GEN = $(if $(filter -dt -bt -b,$(FLAGS)),$(GEN-TCC),$(GEN-CC)) GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS) -GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS) +GEN-TCC = $(T1) GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe MS-CC = cl @@ -108,5 +150,5 @@ MS-CC = cl $(sort $(GEN-ALWAYS) $(UPDATE)) : force force: -clean: - rm -f fred.txt *.output a.exe $(GEN-ALWAYS) +clean : + rm -f fred.txt *.output a.exe *.dll *.so *.def $(GEN-ALWAYS) |