Compare commits

...

4 Commits

Author SHA1 Message Date
herman ten brugge
80e7040d0c tcc loops with some input arguments
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_64-win32 (push) Has been cancelled
build and test / test-i386-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 is one example:
tcc -c a b -o c

Detected with some configure scripts.
2025-08-18 22:28:05 +02:00
grischka
2662b7b43c tccgen: local scope for types of function parameters
int foo(struct xxx {int x[3];} *p) { ...

We want 'xxx' be visible only inside the function. To get that,
the patch removes the 'sym_push(param)' in xxx-gen.c, and instead
(in tccgen.c:gen_function()) pushes all symbols that were newly
defined during parsing of the parameter list in post_type().

Also,
- decl_initializer_alloc():
  patch existing globals earlier, which updates flex arrays too
- let patch_type() do the 'redefinition' check and FUNC_OLD update
2025-08-18 21:06:03 +02:00
grischka
deb7a3fc73 tcc.c:main() free all & etc...
tcc.c:
- be nice to leak checkers
tcctools.c:
- remove unused TCCState params
tccrun.c:
- call bound_exit() after signals to let it free mem
tccelf.c:
- use section_add() instead of section_ptr_add() when
  more appropriate
tccpp.c:
- use size_t to align tal_header naturally
- 'POINTER_SIZE' and 'PTR_SIZE' in the same source is confusing
- "char file_name[TAL_DEBUG_FILE_LEN + 1];" looks silly.
- next_nomacro(): skip UTF8 BOM at BOF
tccgen.c:
- get rid of STMT_EXPR clause on top of block
- warn with useless type like 'int;'
- move skip()'s in block() for better error line-info
- BIT_SIZE bits are meaningful only with VT_BITFIELD
  (not with enums for example)
workflow/test-win32:
- build with MSVC using build-tcc.bat also
alloca.S:
- fix 'off by one' problem on win32 (must touch current page
  too because the 'push %edx' at the end could touch the next page)
- must not align greater than 4 when used for struct args
  (i386-gen.c:gfunc_call())
libtcc.c:
- accept -g1dwarf (dwarf output, only line info)
2025-08-18 20:43:52 +02:00
herman ten brugge
8845b6cd45 Make signed/unsigned bitfields the same as gcc/clang 2025-08-18 16:22:00 +02:00
27 changed files with 567 additions and 401 deletions

View File

@ -31,7 +31,7 @@ jobs:
test-x86_64-win32:
runs-on: windows-2025
timeout-minutes: 4
timeout-minutes: 6
steps:
- uses: actions/checkout@v4
- name: make & test tcc (x86_64-win32)
@ -44,10 +44,22 @@ jobs:
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-x86_64-gcc"
echo ::endgroup::
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
- name: build with MSVC (x86_64-win32)
shell: cmd
run: |
echo ::group:: run build-tcc.bat
cd win32
call build-tcc.bat -t 64 -c cl
echo ::endgroup::
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
test-i386-win32:
runs-on: windows-2025
timeout-minutes: 4
timeout-minutes: 6
steps:
- uses: actions/checkout@v4
- name: make & test tcc (i386-win32)
@ -59,7 +71,19 @@ jobs:
set CHERE_INVOKING=yes
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-i686-gcc"
echo ::endgroup::
C:\msys64\usr\bin\bash -l -c "./configure && make all && make test -k"
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: x86
- name: build with MSVC (i386-win32)
shell: cmd
run: |
echo ::group:: run build-tcc.bat
cd win32
call build-tcc.bat -t 32 -c cl
echo ::endgroup::
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
test-armv7-linux:
runs-on: ubuntu-22.04

View File

@ -1493,8 +1493,7 @@ from_stack:
addr = (n + nf + sn) * 4;
sn += size;
}
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL,
addr + 12);
gfunc_set_param(sym, addr + 12, 0);
}
last_itod_magic=0;
leaffunc = 1;

View File

@ -1242,9 +1242,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
int off = (a[i] < 16 ? 160 + a[i] / 2 * 8 :
a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 :
224 + ((a[i] - 32) >> 1 << 1));
sym_push(sym->v & ~SYM_FIELD, &sym->type,
(a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
off);
gfunc_set_param(sym, off, a[i] & 1);
if (a[i] < 16) {
int align, size = type_size(&sym->type, &align);

View File

@ -1968,7 +1968,7 @@ void gfunc_prolog(Sym *func_sym)
/* define parameters */
while ((sym = sym->next) != NULL) {
type = &sym->type;
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
gfunc_set_param(sym, addr, 0);
size = type_size(type, &align);
size = (size + 3) & ~3;

View File

@ -417,6 +417,7 @@ ST_FUNC void gfunc_call(int nb_args)
/* allocate the necessary size on stack */
#ifdef TCC_TARGET_PE
if (size >= 4096) {
save_reg(TREG_EDX);
r = get_reg(RC_EAX);
oad(0x68, size); // push size
/* cannot call normal 'alloca' with bound checking */
@ -577,8 +578,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
param_addr = addr;
addr += size;
}
sym_push(sym->v & ~SYM_FIELD, type,
VT_LOCAL | VT_LVAL, param_addr);
gfunc_set_param(sym, param_addr, 0);
param_index++;
}
func_ret_sub = 0;

View File

@ -17,13 +17,13 @@ _(__bound_alloca):
mov %eax, %ecx
test %eax,%eax
jz p6
add $15+1,%eax
and $-16,%eax
add $3 + 1,%eax
and $-4,%eax
#ifdef _WIN32
p4:
cmp $4096,%eax
jbe p5
jb p5
test %eax,-4096(%esp)
sub $4096,%esp
sub $4096,%eax
@ -33,7 +33,6 @@ p5:
#endif
sub %eax,%esp
and $-16,%esp
mov %esp,%eax
push %edx
@ -72,12 +71,11 @@ _(__bound_alloca_nr):
#else
pop %rdx
mov %rdi,%rax
and %eax,%eax
jz p3
mov %rax,%rsi # size, a second parm to the __bound_new_region
add $15 + 1,%rax # add one extra to separate regions
and $-16,%rax
jz p3
sub %rax,%rsp
mov %rsp,%rdi # pointer, a first parm to the __bound_new_region

View File

@ -15,14 +15,14 @@ _(alloca):
_(__alloca):
pop %edx
pop %eax
add $15,%eax
and $-16,%eax
add $3,%eax
and $-4,%eax
jz p3
#ifdef _WIN32
p1:
cmp $4096,%eax
jbe p2
jb p2
test %eax,-4096(%esp)
sub $4096,%esp
sub $4096,%eax
@ -30,7 +30,6 @@ p1:
p2:
#endif
sub %eax,%esp
and $-16,%esp
mov %esp,%eax
p3:
push %edx
@ -55,7 +54,7 @@ _(alloca):
#ifdef _WIN32
p1:
cmp $4096,%rax
jbe p2
jb p2
test %rax,-4096(%rsp)
sub $4096,%rsp
sub $4096,%rax

View File

@ -804,7 +804,6 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
s1->error_set_jmp_enabled = 1;
if (setjmp(s1->error_jmp_buf) == 0) {
s1->nb_errors = 0;
if (fd == -1) {
int len = strlen(str);
@ -1816,8 +1815,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
const TCCOption *popt;
const char *optarg, *r;
const char *run = NULL;
int x;
int tool = 0, arg_start = 0, not_empty = 0, optind = 1;
int optind = 1, empty = 1, x;
char **argv = *pargv;
int argc = *pargc;
@ -1836,21 +1834,16 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
continue;
}
optind++;
if (tool) { /* ignore all except -v and @listfile */
s->verbose += !strcmp(r, "-v");
continue;
}
if (r[0] != '-' || r[1] == '\0') { /* file or '-' (stdin) */
args_parser_add_file(s, r, s->filetype);
not_empty = 1;
empty = 0;
dorun:
if (run) {
/* tcc -run <file> <args...> */
if (tcc_set_options(s, run))
if (tcc_set_options(s, run) < 0)
return -1;
arg_start = optind - 1; /* argv[0] will be <file> */
break;
x = 0;
goto extra_action;
}
continue;
}
@ -1923,14 +1916,16 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
case TCC_OPTION_g:
s->do_debug = 2;
s->dwarf = CONFIG_DWARF_VERSION;
g_redo:
if (strstart("dwarf", &optarg)) {
s->dwarf = (*optarg) ? (0 - atoi(optarg)) : DEFAULT_DWARF_VERSION;
} else if (0 == strcmp("stabs", optarg)) {
s->dwarf = 0;
} else if (isnum(*optarg)) {
x = *optarg - '0';
x = *optarg++ - '0';
/* -g0 = no info, -g1 = lines/functions only, -g2 = full info */
s->do_debug = x > 2 ? 2 : x == 0 && s->do_backtrace ? 1 : x;
goto g_redo;
#ifdef TCC_TARGET_PE
} else if (0 == strcmp(".pdb", optarg)) {
s->dwarf = 5, s->do_debug |= 16;
@ -2030,7 +2025,6 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
}
break;
case TCC_OPTION_W:
s->warn_none = 0;
if (optarg[0] && set_flag(s, options_W, optarg) < 0)
goto unsupported_option;
break;
@ -2141,29 +2135,24 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
case TCC_OPTION_ar:
x = OPT_AR;
extra_action:
arg_start = optind - 1;
if (not_empty)
if (NULL == argv[0]) /* from tcc_set_options() */
return -1;
if (!empty && x)
return tcc_error_noabort("cannot parse %s here", r);
tool = x;
break;
--optind;
*pargc = argc - optind;
*pargv = argv + optind;
return x;
default:
unsupported_option:
tcc_warning_c(warn_unsupported)("unsupported option '%s'", r);
break;
}
not_empty = 1;
empty = 0;
}
if (s->link_optind < s->link_argc)
return tcc_error_noabort("argument to '-Wl,%s' is missing", s->link_argv[s->link_optind]);
if (NULL == argv[0]) /* from tcc_set_options() */
return 0;
if (arg_start) {
*pargc = argc - arg_start;
*pargv = argv + arg_start;
return tool;
}
if (not_empty)
if (!empty)
return 0;
if (s->verbose == 2)
return OPT_PRINT_DIRS;

View File

@ -833,9 +833,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
}
}
}
sym_push(sym->v & ~SYM_FIELD, &sym->type,
(byref ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
param_addr);
gfunc_set_param(sym, param_addr, byref);
}
func_va_list_ofs = addr;
num_va_regs = 0;

43
tcc.c
View File

@ -283,51 +283,51 @@ static unsigned getclock_ms(void)
#endif
}
int main(int argc0, char **argv0)
int main(int argc, char **argv)
{
TCCState *s, *s1;
int ret, opt, n = 0, t = 0, done;
unsigned start_time = 0, end_time = 0;
const char *first_file;
int argc; char **argv;
int argc0 = argc;
char **argv0 = argv;
FILE *ppfp = stdout;
redo:
argc = argc0, argv = argv0;
s = s1 = tcc_new();
opt = tcc_parse_args(s, &argc, &argv);
if (opt < 0)
return 1;
if (n == 0) {
ret = 0;
if (opt == OPT_HELP) {
fputs(help, stdout);
if (!s->verbose)
return 0;
++opt;
}
if (opt == OPT_HELP2) {
fputs(help2, stdout);
return 0;
}
if (opt == OPT_M32 || opt == OPT_M64)
return tcc_tool_cross(s, argv, opt);
if (s->verbose)
if (s->verbose)
goto help2;
} else if (opt == OPT_HELP2) {
help2: fputs(help2, stdout);
} else if (opt == OPT_M32 || opt == OPT_M64) {
ret = tcc_tool_cross(argv, opt);
} else if (s->verbose)
printf("%s", version);
if (opt == OPT_AR)
return tcc_tool_ar(s, argc, argv);
ret = tcc_tool_ar(argc, argv);
#ifdef TCC_TARGET_PE
if (opt == OPT_IMPDEF)
return tcc_tool_impdef(s, argc, argv);
ret = tcc_tool_impdef(argc, argv);
#endif
if (opt == OPT_V)
return 0;
if (opt == OPT_PRINT_DIRS) {
/* initialize search dirs */
set_environment(s);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
print_search_dirs(s);
return 0;
}
if (opt < 0) err:
ret = 1, opt = -1;
if (opt) {
tcc_delete(s);
return ret;
}
if (s->nb_files == 0) {
@ -345,7 +345,7 @@ redo:
tcc_error_noabort("cannot specify output file with -c many files");
}
if (s->nb_errors)
return 1;
goto err;
if (s->do_bench)
start_time = getclock_ms();
}
@ -419,7 +419,6 @@ redo:
tcc_print_stats(s, end_time - start_time);
tcc_delete(s);
if (!done)
goto redo;
if (ppfp && ppfp != stdout)

12
tcc.h
View File

@ -95,13 +95,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define O_BINARY 0
#endif
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#ifdef __clang__ // clang -fsanitize compains about: NULL+value
#define offsetof(type, field) __builtin_offsetof(type, field)
#endif
#ifdef __clang__ // clang -fsanitize compains about: NULL+value
#undef offsetof
#define offsetof(type, field) __builtin_offsetof(type, field)
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#ifndef countof
@ -1507,6 +1506,7 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty);
ST_FUNC void gbound_args(int nb_args);
ST_DATA int func_bound_add_epilog;
#endif
ST_FUNC Sym *gfunc_set_param(Sym *s, int c, int byref);
/* ------------ tccelf.c ------------ */
@ -1857,7 +1857,7 @@ ST_FUNC void tcc_debug_eincl(TCCState *s1);
ST_FUNC void tcc_debug_newfile(TCCState *s1);
ST_FUNC void tcc_debug_line(TCCState *s1);
ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e);
ST_FUNC void tcc_add_debug_info(TCCState *s1, Sym *s, Sym *e);
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
ST_FUNC void tcc_debug_prolog_epilog(TCCState *s1, int value);
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);

View File

@ -1625,7 +1625,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
t = t->type.ref;
debug_type = tcc_debug_find(s1, t, 0);
if (debug_type == -1) {
if (debug_type == -1 && t->c >= 0) {
debug_type = tcc_debug_add(s1, t, 0);
cstr_new (&str);
cstr_printf (&str, "%s:T%d=%c%d",
@ -1664,7 +1664,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
Sym *e = t = t->type.ref;
debug_type = tcc_debug_find(s1, t, 0);
if (debug_type == -1) {
if (debug_type == -1 && t->c >= 0) {
debug_type = tcc_debug_add(s1, t, 0);
cstr_new (&str);
cstr_printf (&str, "%s:T%d=e",
@ -1741,7 +1741,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
if ((type & VT_BTYPE) == VT_STRUCT) {
t = t->type.ref;
debug_type = tcc_debug_find(s1, t, 1);
if (debug_type == -1) {
if (debug_type == -1 && t->c >= 0) {
int pos_sib = 0, i, *pos_type;
debug_type = tcc_debug_add(s1, t, 1);
@ -1819,7 +1819,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
else if (IS_ENUM(type)) {
t = t->type.ref;
debug_type = tcc_debug_find(s1, t, 1);
if (debug_type == -1) {
if (debug_type == -1 && t->c >= 0) {
int pos_sib, pos_type;
Sym sym = {0}; sym.type.t = VT_INT | (type & VT_UNSIGNED);
@ -2090,14 +2090,16 @@ static void tcc_debug_finish (TCCState *s1, struct _debug_info *cur)
}
}
ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e)
ST_FUNC void tcc_add_debug_info(TCCState *s1, Sym *s, Sym *e)
{
CString debug_str;
int param;
if (!(s1->do_debug & 2))
return;
cstr_new (&debug_str);
param = !e;
for (; s != e; s = s->prev) {
if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL)
continue;

View File

@ -318,8 +318,7 @@ ST_FUNC size_t section_add(Section *sec, addr_t size, int align)
ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
{
size_t offset = section_add(sec, size, 1);
// clang -fsanitize compains about: NULL+value
return sec->data ? sec->data + offset : (void *)offset;
return sec->data + offset;
}
#ifndef ELF_OBJ_ONLY
@ -1598,7 +1597,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
s = data_section;
/* Align to PTR_SIZE */
section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1));
section_add(s, 0, PTR_SIZE);
o = s->data_offset;
/* create a struct rt_context (see tccrun.c) */
if (s1->dwarf) {
@ -2837,7 +2836,6 @@ static int elf_output_file(TCCState *s1, const char *filename)
int textrel, got_sym, dt_flags_1;
file_type = s1->output_type;
s1->nb_errors = 0;
ret = -1;
interp = dynstr = dynamic = NULL;
sec_order = NULL;
@ -3030,7 +3028,6 @@ static int elf_output_obj(TCCState *s1, const char *filename)
{
Section *s;
int i, ret, file_offset;
s1->nb_errors = 0;
/* Allocate strings for section names */
alloc_sec_names(s1, 1);
file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4;
@ -3049,6 +3046,7 @@ static int elf_output_obj(TCCState *s1, const char *filename)
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename)
{
s->nb_errors = 0;
if (s->test_coverage)
tcc_tcov_add_file(s, filename);
if (s->output_type == TCC_OUTPUT_OBJ)
@ -3254,21 +3252,19 @@ invalid:
s->sh_entsize = sh->sh_entsize;
sm_table[i].new_section = 1;
found:
size = sh->sh_size;
/* align start of section */
s->data_offset += -s->data_offset & (sh->sh_addralign - 1);
offset = section_add(s, size, sh->sh_addralign);
if (sh->sh_addralign > s->sh_addralign)
s->sh_addralign = sh->sh_addralign;
sm_table[i].offset = s->data_offset;
sm_table[i].offset = offset;
sm_table[i].s = s;
/* concatenate sections */
size = sh->sh_size;
if (sh->sh_type != SHT_NOBITS) {
if (sh->sh_type != SHT_NOBITS && size) {
unsigned char *ptr;
lseek(fd, file_offset + sh->sh_offset, SEEK_SET);
ptr = section_ptr_add(s, size);
ptr = s->data + offset;
full_read(fd, ptr, size);
} else {
s->data_offset += size;
}
#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
/* align code sections to instruction lenght */
@ -3310,6 +3306,9 @@ invalid:
}
}
if (!symtab)
goto done;
/* resolve symbols */
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
@ -3405,7 +3404,7 @@ invalid:
break;
}
}
done:
ret = 0;
the_end:
tcc_free(symtab);

384
tccgen.c
View File

@ -683,20 +683,25 @@ ST_INLN Sym *sym_find(int v)
return table_ident[v]->sym_identifier;
}
static int sym_scope(Sym *s)
/* make sym in-/visible to the parser */
static inline void sym_link(Sym *s, int yes)
{
if (IS_ENUM_VAL (s->type.t))
return s->type.ref->sym_scope;
else
return s->sym_scope;
TokenSym *ts = table_ident[(s->v & ~SYM_STRUCT) - TOK_IDENT];
Sym **ps;
if (s->v & SYM_STRUCT)
ps = &ts->sym_struct;
else
ps = &ts->sym_identifier;
if (yes)
s->prev_tok = *ps, *ps = s;
else
*ps = s->prev_tok;
}
/* push a given symbol on the symbol stack */
ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
{
Sym *s, **ps;
TokenSym *ts;
if (local_stack)
ps = &local_stack;
else
@ -706,17 +711,15 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
s->r = r;
/* don't record fields or anonymous symbols */
/* XXX: simplify */
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
/* record symbol in token array */
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
if (v & SYM_STRUCT)
ps = &ts->sym_struct;
else
ps = &ts->sym_identifier;
s->prev_tok = *ps;
*ps = s;
sym_link(s, 1);
s->sym_scope = local_scope;
if (s->prev_tok && sym_scope(s->prev_tok) == s->sym_scope)
if (s->prev_tok
&& (IS_ENUM_VAL (s->prev_tok->type.t)
? s->prev_tok->type.ref->sym_scope
: s->prev_tok->sym_scope)
== s->sym_scope)
tcc_error("redeclaration of '%s'",
get_tok_str(v & ~SYM_STRUCT, NULL));
}
@ -746,8 +749,7 @@ ST_FUNC Sym *global_identifier_push(int v, int t, int c)
pop them yet from the list, but do remove them from the token array. */
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
{
Sym *s, *ss, **ps;
TokenSym *ts;
Sym *s, *ss;
int v;
s = *ptop;
@ -755,15 +757,8 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
ss = s->prev;
v = s->v;
/* remove symbol in token array */
/* XXX: simplify */
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
if (v & SYM_STRUCT)
ps = &ts->sym_struct;
else
ps = &ts->sym_identifier;
*ps = s->prev_tok;
}
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
sym_link(s, 0);
if (!keep)
sym_free(s);
s = ss;
@ -829,6 +824,19 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
*ptop = slast;
}
#if 0
/* debug: print symbols on stack from s ... last */
static inline void psyms(const char *msg, Sym *s, Sym *last)
{
printf("%-8s scope v c r type.t\n", msg);
while (s && s != last) {
printf(" %8x %08x %08x %08x %08x %s\n",
s->sym_scope, s->v, s->c, s->r, s->type.t, get_tok_str(s->v, 0));
s = s->prev;
}
}
#endif
/* ------------------------------------------------------------------------- */
static void vcheck_cmp(void)
{
@ -1219,6 +1227,9 @@ static void patch_type(Sym *sym, CType *type)
} else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
int static_proto = sym->type.t & VT_STATIC;
int ft1 = sym->type.ref->f.func_type;
int ft2 = type->ref->f.func_type;
/* warn if static follows non-static function declaration */
if ((type->t & VT_STATIC) && !static_proto
/* XXX this test for inline shouldn't be here. Until we
@ -1239,15 +1250,14 @@ static void patch_type(Sym *sym, CType *type)
struct FuncAttr f = sym->type.ref->f;
/* put complete type, use static from prototype */
sym->type.t = (type->t & ~(VT_STATIC|VT_INLINE)) | static_proto;
if (ft1 != FUNC_OLD)
type->ref->f.func_type = ft1;
sym->type.ref = type->ref;
merge_funcattr(&sym->type.ref->f, &f);
} else {
sym->type.t &= ~VT_INLINE | static_proto;
}
if (sym->type.ref->f.func_type == FUNC_OLD
&& type->ref->f.func_type != FUNC_OLD) {
sym->type.ref = type->ref;
if (ft1 == FUNC_OLD && ft2 != FUNC_OLD)
sym->type.ref = type->ref;
}
} else {
@ -1284,10 +1294,8 @@ static Sym *sym_copy(Sym *s0, Sym **ps)
Sym *s;
s = sym_malloc(), *s = *s0;
s->prev = *ps, *ps = s;
if (s->v < SYM_FIRST_ANOM) {
ps = &table_ident[s->v - TOK_IDENT]->sym_identifier;
s->prev_tok = *ps, *ps = s;
}
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
sym_link(s, 1);
return s;
}
@ -1677,16 +1685,15 @@ static void add_local_bounds(Sym *s, Sym *e)
}
#endif
/* Wrapper around sym_pop, that potentially also registers local bounds. */
static void pop_local_syms(Sym *b, int keep)
/* add debug info for locals or function parameters, optionally
register bounds */
static void tcc_debug_end_scope(Sym *b, int bounds)
{
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && !keep && (local_scope || !func_var))
if (tcc_state->do_bounds_check && bounds)
add_local_bounds(local_stack, b);
#endif
if (debug_modes)
tcc_add_debug_info (tcc_state, !local_scope, local_stack, b);
sym_pop(&local_stack, b, keep);
tcc_add_debug_info (tcc_state, local_stack, b);
}
/* increment an lvalue pointer */
@ -2959,15 +2966,17 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
if (bt2 == VT_LLONG)
type.t &= t2;
/* convert to unsigned if it does not fit in a long long */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) ||
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
type.t |= VT_UNSIGNED;
} else {
/* integer operations */
type.t = VT_INT | (VT_LONG & (t1 | t2));
/* convert to unsigned if it does not fit in an integer */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
if (((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)
&& (!(t1 & VT_BITFIELD) || BIT_SIZE(t1) == 32))
|| ((t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)
&& (!(t2 & VT_BITFIELD) || BIT_SIZE(t2) == 32)))
type.t |= VT_UNSIGNED;
}
if (dest)
@ -3851,10 +3860,14 @@ static void parse_attribute(AttributeDef *ad)
{
int t, n;
char *astr;
AttributeDef ad_tmp;
redo:
if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2)
return;
if (NULL == ad) /* skip over / ignore attributes */
ad = &ad_tmp;
next();
skip('(');
skip('(');
@ -4509,7 +4522,7 @@ do_decl:
expect("identifier");
else {
int v = btype.ref->v;
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
if (tcc_state->ms_extensions == 0)
expect("identifier");
}
@ -4554,6 +4567,7 @@ do_decl:
tcc_error("width of '%s' exceeds its type",
get_tok_str(v, NULL));
} else if (bit_size == bsize
&& !*tcc_state->pack_stack_ptr
&& !ad.a.packed && !ad1.a.packed) {
/* no need for bit fields */
;
@ -4921,7 +4935,7 @@ static int asm_label_instr(void)
static int post_type(CType *type, AttributeDef *ad, int storage, int td)
{
int n, l, t1, arg_size, align;
Sym **plast, *s, *first;
Sym **plast, *s, *first, **ps, *sr;
AttributeDef ad1;
CType pt;
TokenString *vla_array_tok = NULL;
@ -4932,11 +4946,20 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
next();
if (TYPE_DIRECT == (td & (TYPE_DIRECT|TYPE_ABSTRACT)))
return 0;
/* we push a anonymous symbol which will contain the function prototype */
/* it also serves as a boundary for the function parameter scope */
ps = local_stack ? &local_stack : &global_stack;
++local_scope;
sr = sym_push2(ps, SYM_FIELD, 0, 0);
if (tok == ')')
l = 0;
else if (parse_btype(&pt, &ad1, 0))
l = FUNC_NEW;
else if (td & (TYPE_DIRECT|TYPE_ABSTRACT)) {
sym_pop(ps, sr->prev, 0);
--local_scope;
merge_attr (ad, &ad1);
return 0;
} else
@ -4945,7 +4968,6 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
first = NULL;
plast = &first;
arg_size = 0;
++local_scope;
if (l) {
for(;;) {
/* read param name and compute offset */
@ -4959,7 +4981,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
n = SYM_FIELD;
} else {
n = tok;
pt.t = VT_VOID; /* invalid type */
pt.t = VT_INT | VT_EXTERN; /* default type */
pt.ref = NULL;
next();
}
@ -4968,8 +4990,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
convert_parameter_type(&pt);
arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
/* these symbols may be evaluated for VLArrays (see below, under
nocode_wanted) which is why we push them here as normal symbols
temporarily. Example: int func(int a, int b[++a]); */
nocode_wanted) Example: int func(int a, int b[++a]); */
s = sym_push(n, &pt, VT_LOCAL|VT_LVAL, 0);
*plast = s;
plast = &s->next;
@ -4988,12 +5009,6 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
/* if no parameters, then old type prototype */
l = FUNC_OLD;
skip(')');
/* remove parameter symbols from token table, keep on stack */
if (first) {
sym_pop(local_stack ? &local_stack : &global_stack, first->prev, 1);
for (s = first; s; s = s->next)
s->v |= SYM_FIELD;
}
--local_scope;
/* NOTE: const is ignored in returned type as it has a special
meaning in gcc / C++ */
@ -5006,15 +5021,19 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
skip(']'); /* only handle simple "[]" */
mk_pointer(type);
}
/* we push a anonymous symbol which will contain the function prototype */
ad->f.func_args = arg_size;
ad->f.func_type = l;
s = sym_push(SYM_FIELD, type, 0, 0);
sr->type = *type, s = sr;
s->a = ad->a;
s->f = ad->f;
s->next = first;
type->t = VT_FUNC;
type->ref = s;
/* unlink symbols from the token table, keep on stack */
sym_pop(ps, sr, 1);
//psyms("---", *ps, sr);
} else if (tok == '[') {
int saved_nocode_wanted = nocode_wanted;
/* array definition */
@ -5612,6 +5631,8 @@ ST_FUNC void unary(void)
as statement expressions can't ever be entered from the
outside, so any reactivation of code emission (from labels
or loop heads) can be disabled again after the end of it. */
/* default return value is (void) */
vpushi(0), vtop->type.t = VT_VOID;
block(STMT_EXPR);
/* If the statement expr can be entered, then we retain the current
nocode_wanted state (from e.g. a 'return 0;' in the stmt-expr).
@ -6967,6 +6988,9 @@ static void prev_scope(struct scope *o, int is_expr)
if (o->cl.s != o->prev->cl.s)
block_cleanup(o->prev);
if (debug_modes)
tcc_debug_end_scope(o->lstk, !is_expr);
/* pop locally defined labels */
label_pop(&local_label_stack, o->llstk, is_expr);
@ -6979,7 +7003,7 @@ static void prev_scope(struct scope *o, int is_expr)
tables, though. sym_pop will do that. */
/* pop locally defined symbols */
pop_local_syms(o->lstk, is_expr);
sym_pop(&local_stack, o->lstk, is_expr);
cur_scope = o->prev;
--local_scope;
}
@ -7033,12 +7057,6 @@ static void block(int flags)
struct scope o;
Sym *s;
if (flags & STMT_EXPR) {
/* default return value is (void) */
vpushi(0);
vtop->type.t = VT_VOID;
}
again:
t = tok;
/* If the token carries a value, next() might destroy it. Only with
@ -7054,8 +7072,8 @@ again:
new_scope_s(&o);
skip('(');
gexpr();
skip(')');
a = gvtst(1, 0);
skip(')');
block(0);
if (tok == TOK_ELSE) {
d = gjmp(0);
@ -7073,8 +7091,8 @@ again:
d = gind();
skip('(');
gexpr();
skip(')');
a = gvtst(1, 0);
skip(')');
b = 0;
lblock(&a, &b);
gjmp_addr(d);
@ -7102,8 +7120,6 @@ again:
while (tok != '}') {
decl(VT_LOCAL);
if (tok != '}') {
if (flags & STMT_EXPR)
vpop();
block(flags | STMT_COMPOUND);
}
}
@ -7205,9 +7221,9 @@ again:
skip(TOK_WHILE);
skip('(');
gexpr();
c = gvtst(0, 0);
skip(')');
skip(';');
c = gvtst(0, 0);
gsym_addr(c, d);
gsym(a);
prev_scope_s(&o);
@ -7225,9 +7241,9 @@ again:
new_scope_s(&o);
skip('(');
gexpr();
skip(')');
if (!is_integer_btype(vtop->type.t & VT_BTYPE))
tcc_error("switch value not an integer");
skip(')');
sw->sv = *vtop--; /* save switch value */
a = 0;
b = gjmp(0); /* jump to first case */
@ -7347,11 +7363,9 @@ again:
s->cleanupstate = cur_scope->cl.s;
block_after_label:
{
/* Accept attributes after labels (e.g. 'unused') */
AttributeDef ad_tmp;
parse_attribute(&ad_tmp);
}
/* Accept attributes after labels (e.g. 'unused') */
parse_attribute(NULL);
if (debug_modes)
tcc_tcov_reset_ind(tcc_state);
vla_restore(cur_scope->vla.loc);
@ -8071,20 +8085,32 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
is put in the value stack. If 'has_init' is 2, a special parsing
is done to handle string constants. */
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
int has_init, int v, int global)
int has_init, int v, int scope)
{
int size, align, addr;
TokenString *init_str = NULL;
Section *sec;
Sym *flexible_array;
Sym *sym;
Sym *sym = NULL;
int saved_nocode_wanted = nocode_wanted;
#ifdef CONFIG_TCC_BCHECK
int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
#endif
init_params p = {0};
if (scope == VT_CONST) {
/* see if a global symbol was already defined */
sym = sym_find(v);
if (sym) {
patch_storage(sym, ad, type);
/* we accept several definitions of the same global variable. */
if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)
return;
type = &sym->type;
}
}
/* Always allocate static or global variables */
if (v && (r & VT_VALMASK) == VT_CONST)
nocode_wanted |= DATA_ONLY_WANTED;
@ -8100,12 +8126,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
// (arrays of incomplete types are handled in array parsing)
if (!(type->t & VT_ARRAY))
tcc_error("initialization of incomplete type");
/* If the base type itself was an array type of unspecified size
(like in 'typedef int arr[]; arr x = {1};') then we will
overwrite the unknown size by the real one for this decl.
We need to unshare the ref symbol holding that size. */
type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c);
p.flex_array_ref = type->ref;
} else if (has_init && (type->t & VT_BTYPE) == VT_STRUCT) {
@ -8211,26 +8231,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
vset(type, r, addr);
}
} else {
sym = NULL;
if (v && global) {
/* see if the symbol was already defined */
sym = sym_find(v);
if (sym) {
if (p.flex_array_ref && (sym->type.t & type->t & VT_ARRAY)
&& sym->type.ref->c > type->ref->c) {
/* flex array was already declared with explicit size
extern int arr[10];
int arr[] = { 1,2,3 }; */
type->ref->c = sym->type.ref->c;
size = type_size(type, &align);
}
patch_storage(sym, ad, type);
/* we accept several definitions of the same global variable. */
if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)
goto no_alloc;
}
}
/* allocate symbol in corresponding section */
sec = ad->section;
if (!sec) {
@ -8291,6 +8291,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (type->t & VT_VLA) {
int a;
if (has_init)
tcc_error("variable length array cannot be initialized");
if (NODATA_WANTED)
goto no_alloc;
@ -8373,11 +8376,35 @@ static void func_vla_arg(Sym *sym)
func_vla_arg_code(arg->type.ref);
}
/* set the local stack address for function parameter from gfunc_prolog() */
ST_FUNC Sym *gfunc_set_param(Sym *s, int c, int byref)
{
s = sym_find(s->v);
if (!s) /* unnamed parameters, not enabled */
return NULL;
s->c = c;
if (byref)
s->r = VT_LLOCAL | VT_LVAL;
return s;
}
/* push parameters (and their types), last first */
static void sym_push_params(Sym *ref)
{
Sym *s;
for (s = ref; s->next; s = s->next)
;
for (; s && s != ref; s = s->prev)
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
sym_copy(s, &local_stack);
}
/* parse a function defined by symbol 'sym' and generate its code in
'cur_text_section' */
static void gen_function(Sym *sym)
{
struct scope f = { 0 };
cur_scope = root_scope = &f;
nocode_wanted = 0;
@ -8406,20 +8433,21 @@ static void gen_function(Sym *sym)
/* push a dummy symbol to enable local sym storage */
sym_push2(&local_stack, SYM_FIELD, 0, 0);
local_scope = 1; /* for function parameters */
nb_temp_local_vars = 0;
gfunc_prolog(sym);
tcc_debug_prolog_epilog(tcc_state, 0);
/* push parameters */
sym_push_params(sym->type.ref);
//psyms(funcname, local_stack, 0);
local_scope = 0;
rsym = 0;
nb_temp_local_vars = 0;
gfunc_prolog(sym);
tcc_debug_prolog_epilog(tcc_state, 0);
func_vla_arg(sym);
block(0);
gsym(rsym);
nocode_wanted = 0;
/* reset local stack */
pop_local_syms(NULL, 0);
tcc_debug_end_scope(NULL, !func_var);
tcc_debug_prolog_epilog(tcc_state, 1);
gfunc_epilog();
@ -8428,11 +8456,12 @@ static void gen_function(Sym *sym)
/* patch symbol size */
elfsym(sym)->st_size = ind - func_ind;
cur_text_section->data_offset = ind;
local_scope = 0;
sym_pop(&local_stack, NULL, 0);
label_pop(&global_label_stack, NULL, 0);
sym_pop(&all_cleanups, NULL, 0);
local_scope = 0;
/* It's better to crash than to generate wrong code */
cur_text_section = NULL;
@ -8510,6 +8539,27 @@ static void do_Static_assert(void)
skip(';');
}
#ifdef TCC_TARGET_PE
static void pe_check_linkage(CType *type, AttributeDef *ad)
{
if (!ad->a.dllimport && !ad->a.dllexport)
return;
if (type->t & VT_STATIC)
tcc_error("cannot have dll linkage with static");
if (type->t & VT_TYPEDEF) {
const char *m = ad->a.dllimport ? "im" : "ex";
tcc_warning("'dll%sport' attribute ignored for typedef", m);
ad->a.dllimport = 0;
ad->a.dllexport = 0;
} else if (ad->a.dllimport) {
if ((type->t & VT_BTYPE) == VT_FUNC)
ad->a.dllimport = 0;
else
type->t |= VT_EXTERN;
}
}
#endif
/* 'l' is VT_LOCAL or VT_CONST to define default storage type
or VT_CMP if parsing old style parameter list
or VT_JMP if parsing c99 for decl: for (int i = 0, ...) */
@ -8517,7 +8567,7 @@ static int decl(int l)
{
int v, has_init, r, oldint;
CType type, btype;
Sym *sym, *s;
Sym *sym;
AttributeDef ad, adbase;
ElfSym *esym;
@ -8556,22 +8606,30 @@ static int decl(int l)
}
if (tok == ';') {
if ((btype.t & VT_BTYPE) == VT_STRUCT) {
v = btype.ref->v;
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM)
tcc_warning("unnamed struct/union that defines no instances");
next();
continue;
}
if (IS_ENUM(btype.t)) {
next();
continue;
}
if ((btype.t & VT_BTYPE) == VT_STRUCT
&& (btype.ref->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
; /* struct decl with named tag */
else if (IS_ENUM(btype.t))
; /* enum decl */
else
tcc_warning("useless type defines no instances");
if (l == VT_JMP)
return 1;
next();
continue;
}
while (1) { /* iterate thru each declaration */
type = btype;
ad = adbase;
if ((btype.t & VT_ARRAY) && btype.ref->c < 0) {
/* If the base type itself was an array type of unspecified
size (like in 'typedef int arr[]; arr x = {1};') then
we will overwrite the unknown size by the real one for
this decl. We need to unshare the ref symbol holding
that size. */
type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c);
}
type_decl(&type, &ad, &v, TYPE_DIRECT);
#if 0
{
@ -8589,23 +8647,7 @@ static int decl(int l)
if (sym->f.func_type == FUNC_OLD && l == VT_CONST) {
func_vt = type;
decl(VT_CMP);
/* Allow mixing old/new prototypes
* void func(float a);
* int main(void) { func(1.0); }
* void func(a) float a; { printf("%g\n", a); }
*/
s = sym_find(v);
if (type.ref->next && // skip old func(); definitions
s && s->type.ref &&
s->type.ref->f.func_type == FUNC_NEW) {
sym->f.func_type = FUNC_NEW;
if (!is_compatible_types(&s->type, &type))
tcc_error("incompatible redefinition of '%s'",
get_tok_str(v, NULL));
}
}
if ((type.t & (VT_EXTERN|VT_INLINE)) == (VT_EXTERN|VT_INLINE)) {
/* always_inline functions must be handled as if they
don't generate multiple global defs, even if extern
@ -8634,47 +8676,33 @@ static int decl(int l)
}
#ifdef TCC_TARGET_PE
if (ad.a.dllimport || ad.a.dllexport) {
if (type.t & VT_STATIC)
tcc_error("cannot have dll linkage with static");
if (type.t & VT_TYPEDEF) {
tcc_warning("'%s' attribute ignored for typedef",
ad.a.dllimport ? (ad.a.dllimport = 0, "dllimport") :
(ad.a.dllexport = 0, "dllexport"));
} else if (ad.a.dllimport) {
if ((type.t & VT_BTYPE) == VT_FUNC)
ad.a.dllimport = 0;
else
type.t |= VT_EXTERN;
}
}
pe_check_linkage(&type, &ad);
#endif
if (tok == '{') {
Sym *sa;
if (l != VT_CONST)
tcc_error("cannot use local functions");
if ((type.t & VT_BTYPE) != VT_FUNC)
expect("function definition");
/* reject abstract declarators in function definition
make old style params without decl have int type */
sym = type.ref;
while ((sym = sym->next) != NULL) {
if (!(sym->v & ~SYM_FIELD))
expect("identifier");
if (type.ref->f.func_type == FUNC_OLD &&
sym->type.t == VT_FLOAT)
sym->type.t = VT_DOUBLE;
if (sym->type.t == VT_VOID)
sym->type = int_type;
}
/* apply post-declaraton attributes */
merge_funcattr(&type.ref->f, &ad.f);
/* put function symbol */
type.t &= ~VT_EXTERN;
sym = external_sym(v, &type, 0, &ad);
/* reject abstract declarators in function definition
make old-style float params double */
for (sa = sym->type.ref; (sa = sa->next) != NULL;) {
if (!(sa->v & ~SYM_FIELD))
expect("identifier");
if (sa->type.t == VT_FLOAT
&& sym->type.ref->f.func_type == FUNC_OLD) {
sa->type.t = VT_DOUBLE;
}
}
/* static inline functions are just recorded as a kind
of macro. Their code will be emitted at the end of
the compilation unit only if they are used */
@ -8697,6 +8725,7 @@ static int decl(int l)
}
break;
} else {
has_init = 0;
if (l == VT_CMP) {
/* find parameter in function parameter list */
for (sym = func_vt.ref->next; sym; sym = sym->next)
@ -8708,7 +8737,7 @@ static int decl(int l)
if (type.t & VT_STORAGE) /* 'register' is okay */
tcc_error("storage class specified for '%s'",
get_tok_str(v, NULL));
if (sym->type.t != VT_VOID)
if (!(sym->type.t & VT_EXTERN))
tcc_error("redefinition of parameter '%s'",
get_tok_str(v, NULL));
convert_parameter_type(&type);
@ -8744,9 +8773,9 @@ static int decl(int l)
/* not lvalue if array */
r |= VT_LVAL;
}
has_init = (tok == '=');
if (has_init && (type.t & VT_VLA))
tcc_error("variable length array cannot be initialized");
if (tok == '=')
has_init = 1;
if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST))
|| (type.t & VT_BTYPE) == VT_FUNC
@ -8763,12 +8792,13 @@ static int decl(int l)
r |= VT_CONST;
else
r |= VT_LOCAL;
type.t &= ~VT_EXTERN;
if (has_init)
next();
else if (l == VT_CONST)
/* uninitialized global variables may be overridden */
type.t |= VT_EXTERN;
decl_initializer_alloc(&type, &ad, r, has_init, v, l == VT_CONST);
decl_initializer_alloc(&type, &ad, r, has_init, v, l);
}
if (ad.alias_target && l == VT_CONST) {
@ -8786,7 +8816,7 @@ static int decl(int l)
}
if (tok != ',') {
if (l == VT_JMP)
return 1;
return has_init ? v : 1;
skip(';');
break;
}

36
tccpp.c
View File

@ -102,7 +102,7 @@ ST_FUNC void skip(int c)
if (tok != c) {
char tmp[40];
pstrcpy(tmp, sizeof tmp, get_tok_str(c, &tokc));
tcc_error("'%s' expected (got \"%s\")", tmp, get_tok_str(tok, &tokc));
tcc_error("'%s' expected (got '%s')", tmp, get_tok_str(tok, &tokc));
}
next();
}
@ -117,16 +117,6 @@ ST_FUNC void expect(const char *msg)
#define USE_TAL
#ifdef _MSC_VER
# if defined _M_AMD64 || defined _M_ARM64 || defined _M_ARM64EC || defined _M_IA64 || defined _M_X64
# define POINTER_SIZE 8
# else
# define POINTER_SIZE 4
# endif
#else
# define POINTER_SIZE sizeof(void *)
#endif
#ifndef USE_TAL
#define tal_free(al, p) tcc_free(p)
#define tal_realloc(al, p, size) tcc_realloc(p, size)
@ -143,7 +133,6 @@ ST_FUNC void expect(const char *msg)
#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__)
#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__)
#define TAL_DEBUG_PARAMS , const char *file, int line
#define TAL_DEBUG_FILE_LEN 40
#endif
#define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */
@ -167,13 +156,16 @@ typedef struct TinyAlloc {
} TinyAlloc;
typedef struct tal_header_t {
ALIGNED(POINTER_SIZE) unsigned size;
size_t size; /* word align */
#ifdef TAL_DEBUG
int line_num; /* negative line_num used for double free check */
char file_name[TAL_DEBUG_FILE_LEN + 1];
char file_name[40];
#endif
} tal_header_t;
#define TAL_ALIGN(size) \
(((size) + (sizeof (size_t) - 1)) & ~(sizeof (size_t) - 1))
/* ------------------------------------------------------------------------- */
static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size)
@ -208,7 +200,7 @@ tail_call:
tal_header_t *header = (tal_header_t *)p;
if (header->line_num > 0) {
fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n",
header->file_name, header->line_num, header->size);
header->file_name, header->line_num, (int)header->size);
}
p += header->size + sizeof(tal_header_t);
}
@ -256,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
tal_header_t *header;
void *ret;
int is_own;
unsigned adj_size = (size + POINTER_SIZE - 1) & -POINTER_SIZE;
unsigned adj_size = TAL_ALIGN(size);
TinyAlloc *al = *pal;
tail_call:
@ -266,9 +258,8 @@ tail_call:
header = (tal_header_t *)al->p;
header->size = adj_size;
#ifdef TAL_DEBUG
{ int ofs = strlen(file) - TAL_DEBUG_FILE_LEN;
strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN);
header->file_name[TAL_DEBUG_FILE_LEN] = 0;
{ int ofs = strlen(file) + 1 - sizeof header->file_name;
strcpy(header->file_name, file + (ofs > 0 ? ofs : 0));
header->line_num = line; }
#endif
ret = al->p + sizeof(tal_header_t);
@ -2986,6 +2977,11 @@ maybe_newline:
tok = c;
p++;
break;
case 0xEF: /* UTF8 BOM ? */
if (p[1] == 0xBB && p[2] == 0xBF && p == file->buffer) {
p += 3;
goto redo_no_start;
}
default:
if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */
goto parse_ident_fast;
@ -3637,7 +3633,7 @@ static void putdefs(CString *cs, const char *p)
static void tcc_predefs(TCCState *s1, CString *cs, int is_asm)
{
cstr_printf(cs, "#define __TINYC__ 9%.2s\n", *& TCC_VERSION + 4);
cstr_printf(cs, "#define __TINYC__ 9%.2s\n", &TCC_VERSION[4]);
putdefs(cs, target_machine_defs);
putdefs(cs, target_os_defs);

View File

@ -312,6 +312,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
addr_t mem, addr;
if (NULL == ptr) {
s1->nb_errors = 0;
#ifdef TCC_TARGET_PE
pe_output_file(s1, NULL);
#else
@ -495,10 +496,6 @@ static void bt_link(TCCState *s1)
{
#ifdef CONFIG_TCC_BACKTRACE
rt_context *rc;
#ifdef CONFIG_TCC_BCHECK
void *p;
#endif
if (!s1->do_backtrace)
return;
rc = tcc_get_symbol(s1, "__rt_info");
@ -511,6 +508,7 @@ static void bt_link(TCCState *s1)
rc->prog_base &= 0xffffffff00000000ULL;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
void *p;
if ((p = tcc_get_symbol(s1, "__bound_init")))
((void(*)(void*,int))p)(rc->bounds_start, 1);
}
@ -599,6 +597,13 @@ static void rt_exit(rt_frame *f, int code)
s = rt_find_state(f);
rt_post_sem();
if (s && s->run_lj) {
#ifdef CONFIG_TCC_BCHECK
if (f->fp) { /* called from signal */
void *p = tcc_get_symbol(s, "__bound_exit");
if (p)
((void (*)(void))p)();
}
#endif
if (code == 0)
code = RT_EXIT_ZERO;
((void(*)(void*,int))s->run_lj)(s->run_jb, code);

View File

@ -54,7 +54,7 @@ static int ar_usage(int ret) {
return ret;
}
ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
ST_FUNC int tcc_tool_ar(int argc, char **argv)
{
static const ArHdr arhdr_init = {
"/ ",
@ -360,7 +360,7 @@ the_end:
#ifdef TCC_TARGET_PE
ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv)
ST_FUNC int tcc_tool_impdef(int argc, char **argv)
{
int ret, v, i;
char infile[260];
@ -487,9 +487,9 @@ the_end:
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int option)
ST_FUNC int tcc_tool_cross(char **argv, int option)
{
tcc_error_noabort("-m%d not implemented.", option);
fprintf(stderr, "tcc -m%d not implemented\n", option);
return 1;
}
@ -546,7 +546,7 @@ static int execvp_win32(const char *prog, char **argv)
#define execvp execvp_win32
#endif /* _WIN32 */
ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int target)
ST_FUNC int tcc_tool_cross(char **argv, int target)
{
char program[4096];
char *a0 = argv[0];
@ -565,7 +565,7 @@ ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int target)
if (strcmp(a0, program))
execvp(argv[0] = program, argv);
tcc_error_noabort("could not run '%s'", program);
fprintf(stderr, "tcc: could not run '%s'\n", program);
return 1;
}

View File

@ -79,7 +79,7 @@ endif
all test :
@echo ------------ version ------------
@ASAN_OPTIONS=detect_leaks=0 $(TCC_LOCAL) -v
@$(TCC_LOCAL) -v
@$(MAKE) --no-print-directory -s clean
@$(MAKE) --no-print-directory -s -r _all

View File

@ -1,9 +1,9 @@
int printf(const char*, ...);
#if defined test_56_btype_excess_1
struct A {} int i;
#elif defined test_57_btype_excess_2
char int i;
#elif defined test_58_function_redefinition
int f(void) { return 0; }
int f(void) { return 1; }
@ -253,7 +253,7 @@ int main () {
hello(123);
return 0;
}
int printf(const char*, ...);
#if defined test_func_3
static int hello(int a)
#elif defined test_func_5
@ -272,7 +272,7 @@ int hello(int a)
int xxx[];
#endif
int bar();
int printf(const char*, ...);
int main ()
{
#if !defined test_var_3
@ -333,7 +333,7 @@ int main()
x
#elif defined test_stray_backslash2
int printf(const char*, ...);
int main()
{
#define _S(x) #x
@ -438,7 +438,7 @@ void func(int a, int if);
int amain(int argc, char *argv[static argc + 1])
{
int i;
int printf(const char*, ...);
for (i = 0; i < argc; ++i)
printf("arg[%d] = \"%s\"\n", i, argv[i]);
return 0;
@ -510,10 +510,45 @@ int main()
#ifdef test_reverse_funcargs
# pragma comment(option, "-freverse-funcargs")
#endif
int printf(const char*, ...);
int main()
{
printf(" %d %d %d\n", printf("1"), printf("22"), printf("333"));
}
#elif defined test_scope_1 \
|| defined test_scope_2 \
|| defined test_scope_3
struct xxx {int x[4];};
/* 'ee' not defined outside of function, 'i' not redefined */
int bar(enum ee { a = 12, b = 34 } i, int(*f)(int i))
{
printf("bar %d %d %d\n", i, a, b);
return 0;
}
/* 'xxx' not defined outside of function */
int foo(struct xxx {int x[3];}*p)
{
printf("foo %d", sizeof *p);
return p->x[3];
}
#ifdef test_scope_2
/* incompatible redefinition */
int foo(struct xxx {int x[2];}*p);
#endif
#ifndef test_scope_3
enum ee { a = 1, b };
#endif
struct xxx x = { 11,22,33,44 };
int main(int argc, char **argv)
{
printf(" %d %d\n", foo(&x), sizeof (struct xxx));
enum ee e = b;
bar(13 + e, 0);
}
#endif

View File

@ -1,8 +1,8 @@
[test_56_btype_excess_1]
60_errors_and_warnings.c:2: error: too many basic types
60_errors_and_warnings.c:4: error: too many basic types
[test_57_btype_excess_2]
60_errors_and_warnings.c:5: error: too many basic types
60_errors_and_warnings.c:6: error: too many basic types
[test_58_function_redefinition]
60_errors_and_warnings.c:9: error: redefinition of 'f'
@ -71,10 +71,10 @@
60_errors_and_warnings.c:153: error: expression expected before ','
[test_invalid_2]
60_errors_and_warnings.c:156: error: ';' expected (got "{")
60_errors_and_warnings.c:156: error: ';' expected (got '{')
[test_invalid_3]
60_errors_and_warnings.c:160: error: ',' expected (got "a")
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
@ -179,7 +179,7 @@ bar : 3 ; 3
60_errors_and_warnings.c:372: error: statement expression outside of function
[test_invalid_tokckill]
60_errors_and_warnings.c:375: error: ';' expected (got "3")
60_errors_and_warnings.c:375: error: ';' expected (got '3')
[test_duplicate_member]
60_errors_and_warnings.c:381: error: duplicate member 'a'
@ -188,7 +188,7 @@ bar : 3 ; 3
60_errors_and_warnings.c:394: error: duplicate member 'd'
[test_conflicting_array_definition]
60_errors_and_warnings.c:399: error: incompatible types for redefinition of 'array'
60_errors_and_warnings.c:399: error: too many initializers
[test_incompatible_local_redef]
60_errors_and_warnings.c:406: error: incompatible redefinition of 'localfunctype'
@ -250,3 +250,15 @@ arg[1] = "Y"
[test_reverse_funcargs]
333221 1 2 3
[test_scope_1]
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
foo 12 44 16
bar 15 12 34
[test_scope_2]
60_errors_and_warnings.c:539: error: incompatible types for redefinition of 'foo'
[test_scope_3]
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:549: error: initialization of incomplete type

View File

@ -6,66 +6,106 @@ int printf(const char*, ...);
int main (void)
{
struct {
unsigned ub:3;
unsigned u:32;
unsigned long long ullb:35;
unsigned long long ull:64;
unsigned u3:3;
unsigned u31:31;
unsigned u32:32;
unsigned long ul31:31;
unsigned long ul32:32;
unsigned long long ull31:31;
unsigned long long ull32:32;
unsigned long long ull33:33;
unsigned long long ull64:64;
unsigned char c;
} s = { 1, 1, 1 };
} s = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
promote(s.ub);
promote(s.u);
promote(s.ullb);
promote(s.ull);
promote(s.u3);
promote(s.u31);
promote(s.u32);
promote(s.ul31);
promote(s.ul32);
promote(s.ull31);
promote(s.ull32);
promote(s.ull33);
promote(s.ull64);
promote(s.c);
printf("\n");
promote((1 ? s.ub : 1));
promote((1 ? s.u : 1));
promote((1 ? s.ullb : 1));
promote((1 ? s.ull : 1));
promote((1 ? s.u3 : 1));
promote((1 ? s.u31 : 1));
promote((1 ? s.u32 : 1));
promote((1 ? s.ul31 : 1));
promote((1 ? s.ul32 : 1));
promote((1 ? s.ull31 : 1));
promote((1 ? s.ull32 : 1));
promote((1 ? s.ull33 : 1));
promote((1 ? s.ull64 : 1));
promote((1 ? s.c : 1));
printf("\n");
promote(s.ub << 1);
promote(s.u << 1);
promote(s.ullb << 1);
promote(s.ull << 1);
promote(s.u3 << 1);
promote(s.u31 << 1);
promote(s.u32 << 1);
promote(s.ul31 << 1);
promote(s.ul32 << 1);
promote(s.ull31 << 1);
promote(s.ull32 << 1);
promote(s.ull33 << 1);
promote(s.ull64 << 1);
promote(s.c << 1);
printf("\n");
promote(+s.ub);
promote(+s.u);
promote(+s.ullb);
promote(+s.ull);
promote(+s.u3);
promote(+s.u31);
promote(+s.u32);
promote(+s.ul31);
promote(+s.ul32);
promote(+s.ull31);
promote(+s.ull32);
promote(+s.ull33);
promote(+s.ull64);
promote(+s.c);
printf("\n");
promote(-s.ub);
promote(-s.u);
promote(-s.ullb);
promote(-s.ull);
promote(-s.u3);
promote(-s.u31);
promote(-s.u32);
promote(-s.ul31);
promote(-s.ul32);
promote(-s.ull31);
promote(-s.ull32);
promote(-s.ull33);
promote(-s.ull64);
promote(-s.c);
printf("\n");
promote(~s.ub);
promote(~s.u);
promote(~s.ullb);
promote(~s.ull);
promote(~s.u3);
promote(~s.u31);
promote(~s.u32);
promote(~s.ul31);
promote(~s.ul32);
promote(~s.ull31);
promote(~s.ull32);
promote(~s.ull33);
promote(~s.ull64);
promote(~s.c);
printf("\n");
promote(!s.ub);
promote(!s.u);
promote(!s.ullb);
promote(!s.ull);
promote(!s.u3);
promote(!s.u31);
promote(!s.u32);
promote(!s.ul31);
promote(!s.ul32);
promote(!s.ull31);
promote(!s.ull32);
promote(!s.ull33);
promote(!s.ull64);
promote(!s.c);
printf("\n");
promote(+(unsigned)s.ub);
promote(-(unsigned)s.ub);
promote(~(unsigned)s.ub);
promote(!(unsigned)s.ub);
promote(+(unsigned)s.u3);
promote(-(unsigned)s.u3);
promote(~(unsigned)s.u3);
promote(!(unsigned)s.u3);
return 0;
}

View File

@ -1,46 +1,81 @@
signed : s.ub
unsigned : s.u
signed : s.ullb
unsigned : s.ull
signed : s.u3
signed : s.u31
unsigned : s.u32
signed : s.ul31
unsigned : s.ul32
signed : s.ull31
unsigned : s.ull32
unsigned : s.ull33
unsigned : s.ull64
signed : s.c
signed : (1 ? s.ub : 1)
unsigned : (1 ? s.u : 1)
signed : (1 ? s.ullb : 1)
unsigned : (1 ? s.ull : 1)
signed : (1 ? s.u3 : 1)
signed : (1 ? s.u31 : 1)
unsigned : (1 ? s.u32 : 1)
signed : (1 ? s.ul31 : 1)
unsigned : (1 ? s.ul32 : 1)
signed : (1 ? s.ull31 : 1)
unsigned : (1 ? s.ull32 : 1)
unsigned : (1 ? s.ull33 : 1)
unsigned : (1 ? s.ull64 : 1)
signed : (1 ? s.c : 1)
signed : s.ub << 1
unsigned : s.u << 1
signed : s.ullb << 1
unsigned : s.ull << 1
signed : s.u3 << 1
signed : s.u31 << 1
unsigned : s.u32 << 1
signed : s.ul31 << 1
unsigned : s.ul32 << 1
signed : s.ull31 << 1
unsigned : s.ull32 << 1
unsigned : s.ull33 << 1
unsigned : s.ull64 << 1
signed : s.c << 1
signed : +s.ub
unsigned : +s.u
signed : +s.ullb
unsigned : +s.ull
signed : +s.u3
signed : +s.u31
unsigned : +s.u32
signed : +s.ul31
unsigned : +s.ul32
signed : +s.ull31
unsigned : +s.ull32
unsigned : +s.ull33
unsigned : +s.ull64
signed : +s.c
signed : -s.ub
unsigned : -s.u
signed : -s.ullb
unsigned : -s.ull
signed : -s.u3
signed : -s.u31
unsigned : -s.u32
signed : -s.ul31
unsigned : -s.ul32
signed : -s.ull31
unsigned : -s.ull32
unsigned : -s.ull33
unsigned : -s.ull64
signed : -s.c
signed : ~s.ub
unsigned : ~s.u
signed : ~s.ullb
unsigned : ~s.ull
signed : ~s.u3
signed : ~s.u31
unsigned : ~s.u32
signed : ~s.ul31
unsigned : ~s.ul32
signed : ~s.ull31
unsigned : ~s.ull32
unsigned : ~s.ull33
unsigned : ~s.ull64
signed : ~s.c
signed : !s.ub
signed : !s.u
signed : !s.ullb
signed : !s.ull
signed : !s.u3
signed : !s.u31
signed : !s.u32
signed : !s.ul31
signed : !s.ul32
signed : !s.ull31
signed : !s.ull32
signed : !s.ull33
signed : !s.ull64
signed : !s.c
unsigned : +(unsigned)s.ub
unsigned : -(unsigned)s.ub
unsigned : ~(unsigned)s.ub
signed : !(unsigned)s.ub
unsigned : +(unsigned)s.u3
unsigned : -(unsigned)s.u3
unsigned : ~(unsigned)s.u3
signed : !(unsigned)s.u3

View File

@ -102,7 +102,6 @@ GEN-ALWAYS =
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
-e 's;0x[0-9A-Fa-f]\{1,\};0x?;g'
112_backtrace.test: LEAK=ASAN_OPTIONS=detect_leaks=0
# this test creates two DLLs and an EXE
113_btdll.test: T1 = \
@ -137,7 +136,7 @@ all test tests2.all: $(filter-out $(SKIP),$(TESTS))
@echo Test: $*...
@$(call T1,$<) $(T3)
T1 = $(LEAK) $(TCC) $(FLAGS) $(T2) $(ARGS)
T1 = $(TCC) $(FLAGS) $(T2) $(ARGS)
T2 = $(if $(NORUN),$1 -o $(basename $@).exe && ./$(basename $@).exe,-run $1)
T3 = $(FILTER) >$*.output 2>&1 || true \
&& diff -Nbu $(filter %.expect,$^) $*.output \

View File

@ -132,6 +132,10 @@ if %TX%==32 echo>> ..\config.h #ifdef TCC_TARGET_I386
echo>> ..\config.h #define CONFIG_TCC_CROSSPREFIX "%PX%-"
echo>> ..\config.h #endif
@rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1
@rem %CC% -DC2STR ..\conftest.c -o c2str.exe
@rem .\c2str.exe ../include/tccdefs.h ../tccdefs_.h
for %%f in (*tcc.exe *tcc.dll) do @del %%f
@if _%TCC_C%_==__ goto compiler_2parts
@ -200,8 +204,9 @@ exit /B %ERRORLEVEL%
.\tcc -B. -m%1 -c ../lib/alloca.S
.\tcc -B. -m%1 -c ../lib/alloca-bt.S
.\tcc -B. -m%1 -c ../lib/stdatomic.c
.\tcc -B. -m%1 -c ../lib/atomic.S
.\tcc -B. -m%1 -c ../lib/builtin.c
.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o builtin.o
.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o
.\tcc -B. -m%1 -c ../lib/bcheck.c -o lib/%2bcheck.o -bt -I..
.\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o
.\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o

View File

@ -376,10 +376,16 @@ extern "C" {
_CRTIMP int __cdecl _set_error_mode(int _Mode);
void __cdecl srand(unsigned int _Seed);
double __cdecl strtod(const char *_Str,char **_EndPtr);
float __cdecl strtof(const char *nptr, char **endptr);
#if !defined __NO_ISOCEXT /* in libmingwex.a */
#if __TINYC__
__CRT_INLINE float __cdecl strtof (const char *p, char ** e) { return strtod(p, e); }
__CRT_INLINE long double __cdecl strtold(const char *p, char ** e) { return strtod(p, e); }
#else
float __cdecl strtof (const char * __restrict__, char ** __restrict__);
long double __cdecl strtold(const char * __restrict__, char ** __restrict__);
#endif
#else
float __cdecl strtof(const char *nptr, char **endptr);
#endif /* __NO_ISOCEXT */
_CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale);
long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix);

View File

@ -859,7 +859,7 @@ extern "C" {
}
#endif
#ifndef !defined (InterlockedAnd64)
#ifndef InterlockedAnd64
#define InterlockedAnd64 InterlockedAnd64_Inline
__CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) {

View File

@ -975,8 +975,7 @@ void gfunc_prolog(Sym *func_sym)
if (reg_param_index < REGN) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
}
sym_push(sym->v & ~SYM_FIELD, type,
VT_LLOCAL | VT_LVAL, addr);
gfunc_set_param(sym, addr, 1);
} else {
if (reg_param_index < REGN) {
/* save arguments passed by register */
@ -989,8 +988,7 @@ void gfunc_prolog(Sym *func_sym)
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
}
}
sym_push(sym->v & ~SYM_FIELD, type,
VT_LOCAL | VT_LVAL, addr);
gfunc_set_param(sym, addr, 0);
}
addr += 8;
reg_param_index++;
@ -1587,8 +1585,7 @@ void gfunc_prolog(Sym *func_sym)
}
default: break; /* nothing to be done for x86_64_mode_none */
}
sym_push(sym->v & ~SYM_FIELD, type,
VT_LOCAL | VT_LVAL, param_addr);
gfunc_set_param(sym, param_addr, 0);
}
#ifdef CONFIG_TCC_BCHECK