mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-20 03:44:19 +08:00
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled
This makes attribute cleanup code work the same as gcc and also makes bound checking a very little bit faster. tcc.h: Add save_return_reg(CType *) and restore_return_reg(CType *) Change gfunc_epilog() to gfunc_epilog(Sym *) arm-gen.c: arm64-gen.c: c67-gen.c: i386-gen.c: il-gen.c: riscv64-gen.c: x86_64-gen.c: Move save and restore register around bound_local_delete call to save_return_reg and restore_return_reg. Pass func_type from gfunc_epilog to gen_bounds_epilog. tccgen.c: Call save_return_reg/restore_return_reg in try_call_scope_cleanup when RETURN is found. tccrun.c: Fix warning when bound checking not used. tests/tests2/101_cleanup.c tests/tests2/101_cleanup.expect Extra checks attribute cleanup save/restore registers. tests/tests2/Makefile: Fix when bound checking not used.
310 lines
6.2 KiB
C
310 lines
6.2 KiB
C
extern int printf(const char*, ...);
|
|
static int glob_i = 0;
|
|
|
|
typedef struct { int a; int b; int c; int d; int e; int f; int g; int h; } tstl;
|
|
typedef struct { int a; int b; int c; int d; } tsti;
|
|
typedef struct { double a; double b; } tstd;
|
|
typedef struct { long double a; } tstld;
|
|
|
|
void incr_glob_i(int *i)
|
|
{
|
|
glob_i += *i;
|
|
*i = -1;
|
|
}
|
|
|
|
#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;
|
|
}
|
|
}
|
|
*j = -1;
|
|
return;
|
|
}
|
|
|
|
void check_oh_i(char *oh_i)
|
|
{
|
|
printf("c: %c\n", *oh_i);
|
|
*oh_i = '0';
|
|
}
|
|
|
|
void goto_hell(double *f)
|
|
{
|
|
printf("oo: %f\n", *f);
|
|
*f = -1.0;
|
|
}
|
|
|
|
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);
|
|
*ip = -1;
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
void my_cleanup1(int *p) {
|
|
printf("%d\n", *p);
|
|
*p = 0x90;
|
|
}
|
|
|
|
int test_cleanup1(void) {
|
|
int __attribute__((cleanup(my_cleanup1))) n = 42;
|
|
return n;
|
|
}
|
|
|
|
void my_cleanup2(tstl *p) {
|
|
printf("%d %d %d %d %d %d %d %d\n", p->a, p->b, p->c, p->d,
|
|
p->e, p->f, p->g, p->h);
|
|
p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93;
|
|
p->e = 0x94; p->f = 0x95; p->g = 0x96; p->h = 0x97;
|
|
}
|
|
|
|
tstl test_cleanup2(void) {
|
|
tstl __attribute__((cleanup(my_cleanup2))) n;
|
|
n.a = 42; n.b = 43; n.c = 44; n.d = 45;
|
|
n.e = 46; n.f = 47; n.g = 48; n.h = 49;
|
|
return n;
|
|
}
|
|
|
|
void my_cleanup3(tsti *p) {
|
|
printf("%d %d %d %d\n", p->a, p->b, p->c, p->d);
|
|
p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93;
|
|
}
|
|
|
|
tsti test_cleanup3(void) {
|
|
tsti __attribute__((cleanup(my_cleanup3))) n;
|
|
n.a = 42; n.b = 43; n.c = 44; n.d = 45;
|
|
return n;
|
|
}
|
|
|
|
void my_cleanup4(tstd *p) {
|
|
printf("%g %g\n", p->a, p->b);
|
|
p->a = 90.0; p->b = 91.0;
|
|
}
|
|
|
|
tstd test_cleanup4(void) {
|
|
tstd __attribute__((cleanup(my_cleanup4))) n;
|
|
n.a = 42.0; n.b = 43.0;
|
|
return n;
|
|
}
|
|
|
|
void my_cleanup5(tstld *p) {
|
|
printf("%Lf\n", p->a);
|
|
p->a = 90.0;
|
|
}
|
|
|
|
tstld test_cleanup5(void) {
|
|
tstld __attribute__((cleanup(my_cleanup5))) n;
|
|
n.a = 42.0;
|
|
return n;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
int i __attribute__ ((__cleanup__(check))) = 0, not_i;
|
|
int chk = 0;
|
|
(void)not_i;
|
|
tstl tl;
|
|
tsti ti;
|
|
tstd td;
|
|
tstld tld;
|
|
|
|
{
|
|
__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();
|
|
printf("%d\n", test_cleanup1());
|
|
tl = test_cleanup2();
|
|
printf("%d %d %d %d %d %d %d %d\n", tl.a, tl.b, tl.c, tl.d,
|
|
tl.e, tl.f, tl.g, tl.h);
|
|
ti = test_cleanup3();
|
|
printf("%d %d %d %d\n", ti.a, ti.b, ti.c, ti.d);
|
|
td = test_cleanup4();
|
|
printf("%g %g\n", td.a, td.b);
|
|
tld = test_cleanup5();
|
|
printf("%Lf\n", tld.a);
|
|
return i;
|
|
}
|
|
|
|
void check2(char **hum)
|
|
{
|
|
printf("str: %s\n", *hum);
|
|
*hum = "fail";
|
|
}
|