tccgen: void values, etc...

originally, this was meant to avoid 'void' values leak
to the gen-xxx.c generators which would otherwise try
to load void from/to registers.  Also catch invalid types
such as 'unsigned bool' eariler.

tccgen.c:
- expr_cond()/gexpr(): ignore VT_VOID
- gen_cast(): set float reg with static initializers to make
  backends happier with invalid input
- init_putv():
  improve static compound literal initializers
Also:
- ignore "missing prototype" and "might return no value"
  for old style K&R functions

tcc.c, libtcc.c:
- tcc_set_output_type(): return errors from loading crt1.o

tcc.h/tccpp.c:
- fix horrible longstanding mistake with sizeof SValue.tab.
  Must have place for sizeof (long double) rather than the
  target's LDOUBLE_SIZE.

tccdefs.h:
- add a fake __[u]int128_t for all platforms

arm-gen.c:
- gen_cvt_ftof() must load to reg always

arm64-gen.c:
- simplify arm64_pcs() a bit

i386/x86_64-gen.c:
- do not assume char is signed (for cross compilation arm->x86)

tccelf/macho linker message:
- instead of
      "undefined symbol 'X'"
  now say
      "unresolved reference to 'X'"
  which makes it more clear that it is a _linker_error_.

tccasm.c:
- .align/p2align: use 'nop's in exec sections
This commit is contained in:
grischka 2026-01-10 21:51:08 +01:00
parent 016087c954
commit 7e01b20362
15 changed files with 161 additions and 151 deletions

View File

@ -2283,8 +2283,9 @@ void gen_cvt_ftoi(int t)
void gen_cvt_ftof(int t)
{
#ifdef TCC_ARM_VFP
uint32_t r = gv(RC_FLOAT);
if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
uint32_t r = vfpr(gv(RC_FLOAT));
r = vfpr(r);
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
}
#else

View File

@ -278,7 +278,6 @@ static int arm64_type_size(int t)
case VT_DOUBLE: return 3;
case VT_LDOUBLE: return 4;
case VT_BOOL: return 0;
case VT_VOID: return 0;
}
assert(0);
return 0;
@ -832,11 +831,10 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
for (i = 0; i < n; i++) {
int hfa = arm64_hfa(type[i], 0);
int win_vararg_float = 0;
int size, align;
int size, align, bt;
if ((type[i]->t & VT_ARRAY) ||
(type[i]->t & VT_BTYPE) == VT_FUNC)
bt = type[i]->t & VT_BTYPE;
if (bt == VT_PTR || bt == VT_FUNC)
size = align = 8;
else
size = type_size(type[i], &align);
@ -848,13 +846,10 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
}
#elif defined(TCC_TARGET_PE)
if (variadic && i >= variadic && (hfa || is_float(type[i]->t))) {
if (variadic && i >= variadic) {
hfa = 0;
if (is_float(type[i]->t)) {
win_vararg_float = 1;
size = 8;
align = 8;
}
if (is_float(bt))
bt = VT_INT, size = align = 8;
}
#endif
if (hfa)
@ -871,12 +866,12 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
}
continue;
}
else if ((type[i]->t & VT_BTYPE) == VT_STRUCT)
else if (bt == VT_STRUCT)
// B.4
size = (size + 7) & ~7;
// C.1
if (!win_vararg_float && is_float(type[i]->t) && nv < 8) {
if (is_float(bt) && nv < 8) {
a[i] = 16 + (nv++ << 1);
continue;
}
@ -895,24 +890,24 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
}
// C.4
if (hfa || (type[i]->t & VT_BTYPE) == VT_LDOUBLE) {
if (hfa || bt == VT_LDOUBLE) {
ns = (ns + 7) & ~7;
ns = (ns + align - 1) & -align;
}
// C.5
if ((type[i]->t & VT_BTYPE) == VT_FLOAT)
if (bt == VT_FLOAT)
size = 8;
// C.6
if (!win_vararg_float && (hfa || is_float(type[i]->t))) {
if (hfa || is_float(bt)) {
a[i] = ns;
ns += size;
continue;
}
// C.7
if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size <= 8 && nx < 8) {
if (bt != VT_STRUCT && size <= 8 && nx < 8) {
a[i] = nx++ << 1;
continue;
}
@ -922,14 +917,14 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
nx = (nx + 1) & ~1;
// C.9
if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size == 16 && nx < 7) {
if (bt != VT_STRUCT && size == 16 && nx < 7) {
a[i] = nx << 1;
nx += 2;
continue;
}
// C.10
if ((type[i]->t & VT_BTYPE) == VT_STRUCT && size <= (8 - nx) * 8) {
if (bt == VT_STRUCT && size <= (8 - nx) * 8) {
a[i] = nx << 1;
nx += (size + 7) >> 3;
continue;
@ -943,7 +938,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
ns = (ns + align - 1) & -align;
// C.13
if ((type[i]->t & VT_BTYPE) == VT_STRUCT) {
if (bt == VT_STRUCT) {
a[i] = ns;
ns += size;
continue;
@ -974,11 +969,11 @@ static unsigned long arm64_pcs(int variadic, int n, CType **type, unsigned long
}
// Argument types:
stack = arm64_pcs_aux(variadic, n, type + 1, a + 1);
stack = arm64_pcs_aux(variadic, n - 1, type + 1, a + 1);
if (0) {
int i;
for (i = 0; i <= n; i++) {
for (i = 0; i < n; i++) {
if (!i)
printf("arm64_pcs return: ");
else
@ -1076,9 +1071,9 @@ ST_FUNC void gfunc_call(int nb_args)
stack = arm64_pcs(
#ifdef TCC_TARGET_PE
old_style ? -1 :
old_style ? /* all args like varargs in K&R style */ -1 :
#endif
var_nb_arg, nb_args, t, a);
var_nb_arg, nb_args + 1, t, a);
// Allocate space for structs replaced by pointer:
for (i = nb_args; i; i--)
@ -1258,7 +1253,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
CType *func_type = &func_sym->type;
int n = 0;
int i = 0;
int pcs_n;
Sym *sym;
CType **t;
unsigned long *a;
@ -1266,35 +1260,32 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
int last_int = 0;
int last_float = 0;
int variadic = func_sym->type.ref->f.func_type == FUNC_ELLIPSIS;
int var_nb_arg = n_func_args(&func_sym->type);
int c;
int var_nb_arg = variadic ? n_func_args(&func_sym->type) : 0;
func_vc = 144; // offset of where x8 is stored
for (sym = func_type->ref; sym; sym = sym->next)
++n;
pcs_n = n - 1;
c = n + variadic;
t = tcc_malloc(c * sizeof(*t));
a = tcc_malloc(c * sizeof(*a));
#ifdef TCC_TARGET_PE
n += variadic;
#endif
t = tcc_malloc(n * sizeof(*t));
a = tcc_malloc(n * sizeof(*a));
for (sym = func_type->ref; sym; sym = sym->next)
t[i++] = &sym->type;
#ifdef TCC_TARGET_PE
if (variadic) {
t[i++] = &int_type;
++pcs_n;
}
if (variadic)
t[i] = &int_type;
#endif
arm64_func_va_list_stack = arm64_pcs(variadic ? var_nb_arg : 0,
pcs_n, t, a);
arm64_func_va_list_stack = arm64_pcs(var_nb_arg, n, t, a);
#ifdef TCC_TARGET_PE
if (variadic)
arm64_func_va_list_stack = arm64_pe_param_off(a[n]);
arm64_func_va_list_stack = arm64_pe_param_off(a[n - 1]);
#endif
#if !defined(TCC_TARGET_MACHO)
@ -1304,6 +1295,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
last_float = 4;
}
#endif
if (a && a[0] == 1)
use_x8 = 1;
for (i = 1, sym = func_type->ref->next; sym; i++, sym = sym->next) {
@ -1563,7 +1555,8 @@ ST_FUNC void gfunc_return(CType *func_type)
CType *t = func_type;
unsigned long a;
arm64_pcs(0, 0, &t, &a);
arm64_pcs(0, 1, &t, &a);
switch (a) {
case -1:
break;

View File

@ -271,7 +271,7 @@ static void gen_modrm(int opc, int op_r2, int r, Sym *sym, int c)
} else if ((r & VT_VALMASK) == VT_LOCAL) {
o(opc);
/* currently, we use only ebp as base */
if (c == (char)c) {
if (c == (signed char)c) {
/* short reference */
o(0x45 | op_reg);
g(c);
@ -439,7 +439,7 @@ ST_FUNC void store(int r, SValue *v)
static void gadd_sp(int val)
{
if (val == (char)val) {
if (val == (signed char)val) {
o(0xc483);
g(val);
} else {
@ -774,7 +774,7 @@ ST_FUNC void gjmp_addr(int a)
{
int r;
r = a - ind - 2;
if (r == (char)r) {
if (r == (signed char)r) {
g(0xeb);
g(r);
} else {
@ -787,7 +787,7 @@ ST_FUNC void gjmp_addr(int a)
ST_FUNC void gjmp_cond_addr(int a, int op)
{
int r = a - ind - 2;
if (r == (char)r)
if (r == (signed char)r)
g(op - 32), g(r);
else
g(0x0f), gjmp2(op - 16, r - 4);
@ -830,7 +830,7 @@ ST_FUNC void gen_opi(int op)
r = gv(RC_INT);
vswap();
c = vtop->c.i;
if (c == (char)c) {
if (c == (signed char)c) {
/* generate inc and dec for smaller code */
if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
opc = (c == 1) ^ (op == '+');

View File

@ -90,8 +90,6 @@
#define __NO_TLS 1
#define __RUNETYPE_INTERNAL 1
# if __SIZEOF_POINTER__ == 8
/* FIXME, __int128_t is used by setjump */
#define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); }
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_PTRDIFF_T__ 8
#else
@ -142,12 +140,6 @@
#endif
#define __INT32_TYPE__ int
#if defined __aarch64__
/* GCC's __uint128_t appears in some Linux/OSX header files. Make it a
synonym for long double to get the size and alignment right. */
#define __uint128_t long double
#endif
#if !defined _WIN32
/* glibc defines. We do not support __USER_NAME_PREFIX__ */
#define __REDIRECT(name, proto, alias) name proto __asm__ (#alias)
@ -187,6 +179,12 @@
# endif
#endif
/* GCC's __uint128_t appears in some Linux/OSX header files.
Just make it some type with same size and alignment. */
struct __uint128__ { char x[16]; } __attribute((__aligned__(16)));
#define __int128_t struct __uint128__
#define __uint128_t struct __uint128__
/* __builtin_va_list */
#if defined __x86_64__
#if !defined _WIN32

View File

@ -252,7 +252,7 @@ static void *default_reallocator(void *ptr, unsigned long size)
else {
ptr1 = realloc(ptr, size);
if (!ptr1) {
fprintf(stderr, "memory full\n");
fprintf(stderr, "tcc: memory full\n");
exit (1);
}
}
@ -1003,9 +1003,9 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
/* paths for crt objects */
tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib)
tccelf_add_crtbegin(s);
tccelf_add_crtbegin(s); /* may produce errors */
#endif
return 0;
return s->nb_errors ? -1 : 0;
}
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)

16
tcc.c
View File

@ -35,7 +35,7 @@ static const char help[] =
"General options:\n"
" -c compile only - generate an object file\n"
" -o outfile set output filename\n"
" -run run compiled source [with custom stdin: -rstdin FILE]\n"
" -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n"
@ -105,6 +105,7 @@ static const char help2[] =
" -static link to static libraries (not recommended)\n"
" -dumpversion print version\n"
" -print-search-dirs print search paths\n"
" -rstdin file with -run: use 'file' as custom stdin\n"
" -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n"
" -arch -C --param -pedantic -pipe -s -traditional\n"
@ -354,9 +355,10 @@ redo:
set_environment(s);
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type);
ret = tcc_set_output_type(s, s->output_type);
if (ppfp)
s->ppfp = ppfp;
if ((s->output_type == TCC_OUTPUT_MEMORY
|| s->output_type == TCC_OUTPUT_PREPROCESS)
&& (s->dflag & 16)) { /* -dt option */
@ -369,7 +371,7 @@ redo:
/* compile or add each files or library */
first_file = NULL;
do {
while (0 == ret) {
struct filespec *f = s->files[n];
s->filetype = f->type;
if (f->type & AFF_TYPE_LIB) {
@ -381,9 +383,11 @@ redo:
first_file = f->name;
ret = tcc_add_file(s, f->name);
}
} while (++n < s->nb_files
&& 0 == ret
&& (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
if (++n == s->nb_files)
break;
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r)
break;
}
if (s->do_bench)
end_time = getclock_ms();

9
tcc.h
View File

@ -475,6 +475,9 @@ typedef struct CType {
struct Sym *ref;
} CType;
/* long double words on host(!) platform */
#define LDOUBLE_WORDS ((sizeof(long double)+3)/4)
/* constant value */
typedef union CValue {
long double ld;
@ -485,7 +488,7 @@ typedef union CValue {
char *data;
int size;
} str;
int tab[LDOUBLE_SIZE/4];
int tab[LDOUBLE_WORDS];
} CValue;
/* value on stack */
@ -1446,8 +1449,8 @@ ST_DATA int nocode_wanted; /* true if no code generation wanted for an expressio
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
ST_DATA int func_ind;
ST_DATA int func_vc; /* stack address for implicit struct return storage */
ST_DATA int func_ind; /* function start address */
ST_DATA const char *funcname;
ST_FUNC void tccgen_init(TCCState *s1);

View File

@ -510,7 +510,7 @@ static void pop_section(TCCState *s1)
static void asm_parse_directive(TCCState *s1, int global)
{
int n, offset, v, size, tok1;
int n, offset, v, size, tok1, c;
Section *sec;
uint8_t *ptr;
@ -540,18 +540,25 @@ static void asm_parse_directive(TCCState *s1, int global)
/* the section must have a compatible alignment */
if (sec->sh_addralign < n)
sec->sh_addralign = n;
c = sec->sh_flags & SHF_EXECINSTR;
} else {
if (n < 0)
n = 0;
size = n;
size = n, c = 0;
}
v = 0;
if (tok == ',') {
next();
v = asm_int_expr(s1);
v = asm_int_expr(s1), c = 0;
}
zero_pad:
if ((uint64_t)ind + size >= 1<<30)
tcc_error("too much data");
if (sec->sh_type != SHT_NOBITS) {
if (c) {
gen_fill_nops(size);
break;
}
sec->data_offset = ind;
ptr = section_ptr_add(sec, size);
memset(ptr, v, size);
@ -706,11 +713,9 @@ static void asm_parse_directive(TCCState *s1, int global)
expect("constant or same-section symbol");
n += esym->st_value;
}
if (n < 0 || n > 0x100000)
tcc_error(".org out of range");
if (n < ind)
tcc_error("attempt to .org backwards");
v = 0;
v = c = 0;
size = n - ind;
goto zero_pad;
}

View File

@ -1106,7 +1106,7 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
if (sym_bind == STB_WEAK)
sym->st_value = 0;
else
tcc_error_noabort("undefined symbol '%s'", name);
tcc_error_noabort("unresolved reference to '%s'", name);
} else if (sh_num < SHN_LORESERVE) {
/* add section base */
@ -2074,7 +2074,7 @@ static void bind_exe_dynsyms(TCCState *s1, int is_PIE)
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
!strcmp(name, "_fp_hw")) {
} else {
tcc_error_noabort("undefined symbol '%s'", name);
tcc_error_noabort("unresolved reference to '%s'", name);
}
}
}
@ -2105,7 +2105,7 @@ static void bind_libs_dynsyms(TCCState *s1)
if (esym->st_shndx == SHN_UNDEF) {
/* weak symbols can stay undefined */
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
tcc_warning("undefined dynamic symbol '%s'", name);
tcc_warning("unresolved dynamic reference to '%s'", name);
}
}
}
@ -3301,6 +3301,8 @@ invalid:
continue;
if (sh->sh_type != s->sh_type
&& strcmp (s->name, ".eh_frame")
/* some crt1.o seem to have two ".note.GNU-stack" (SHT_NOTE & SHT_PROGBITS) */
&& strcmp (s->name, ".note.GNU-stack")
) {
tcc_error_noabort("section type conflict: %s %02x <> %02x", s->name, sh->sh_type, s->sh_type);
goto the_end;

View File

@ -70,8 +70,9 @@ ST_DATA int nocode_wanted; /* no code generation wanted */
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
ST_DATA int func_vc;
ST_DATA int func_ind;
ST_DATA int func_vc; /* stack address for implicit struct return storage */
ST_DATA int func_ind; /* function start address */
static int func_old;
ST_DATA const char *funcname;
ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;
static CString initstr;
@ -1385,7 +1386,7 @@ static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
/* make sure that type->ref is on global stack */
move_ref_to_global(s);
/* put into local scope */
s = sym_copy(s, &local_stack);
sym_copy(s, &local_stack);
}
return s;
}
@ -1906,6 +1907,8 @@ ST_FUNC int gv(int rc)
#endif
bt = vtop->type.t & VT_BTYPE;
if (bt == VT_VOID || bt == VT_STRUCT) /* should not happen */
return vtop->r;
#ifdef TCC_TARGET_RISCV64
/* XXX mega hack */
@ -2929,7 +2932,8 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
type.ref = NULL;
if (bt1 == VT_VOID || bt2 == VT_VOID) {
ret = op == '?' ? 1 : 0;
if (op != '?')
tcc_error("operation on void value");
/* NOTE: as an extension, we accept void on only one side */
type.t = VT_VOID;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
@ -3176,7 +3180,7 @@ op_err:
}
// Make sure that we have converted to an rvalue:
if (vtop->r & VT_LVAL)
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
gv(RC_TYPE(vtop->type.t));
}
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM
@ -3281,8 +3285,10 @@ again:
df = is_float(dbt);
dbt_bt = dbt & VT_BTYPE;
sbt_bt = sbt & VT_BTYPE;
if (dbt_bt == VT_VOID)
if (dbt_bt == VT_VOID) {
vtop->r = vtop->r2 = VT_CONST;
goto done;
}
if (sbt_bt == VT_VOID) {
error:
cast_error(&vtop->type, type);
@ -3361,8 +3367,11 @@ error:
}
/* cannot generate code for global or static initializers */
if (nocode_wanted & DATA_ONLY_WANTED)
if (nocode_wanted & DATA_ONLY_WANTED) {
if (df)
vtop->r = get_reg(RC_FLOAT); /* don't confuse backends */
goto done;
}
/* non constant case: generate code */
if (dbt == VT_BOOL) {
@ -4753,6 +4762,8 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
} else {
if (bt != -1 || (st != -1 && u != VT_INT))
goto tmbt;
if ((t & VT_DEFSIGN) && (u == VT_VOID || u > VT_LLONG))
goto tmbt;
bt = u;
}
if (u != VT_INT)
@ -6112,6 +6123,7 @@ special_math_val:
tcc_error("'%s' undeclared", name);
/* for simple function calls, we tolerate undeclared
external reference to int() function */
if (!func_old)
tcc_warning_c(warn_implicit_function_declaration)(
"implicit declaration of function '%s'", name);
s = external_global_sym(t, &func_old_type);
@ -6660,7 +6672,7 @@ static void expr_cond(void)
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
that `(expr ? a : b).mem` does not error with "lvalue expected" */
islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
islv = VT_STRUCT == (type.t & VT_BTYPE);
/* now we convert second operand */
if (c != 1) {
@ -6668,8 +6680,7 @@ static void expr_cond(void)
if (islv) {
mk_pointer(&vtop->type);
gaddrof();
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof();
}
}
rc = RC_TYPE(type.t);
@ -6680,6 +6691,7 @@ static void expr_cond(void)
tt = r2 = 0;
if (c < 0) {
if (type.t != VT_VOID)
r2 = gv(rc);
tt = gjmp(0);
}
@ -6695,14 +6707,15 @@ static void expr_cond(void)
if (islv) {
mk_pointer(&vtop->type);
gaddrof();
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof();
}
}
if (c < 0) {
if (type.t != VT_VOID) {
r1 = gv(rc);
move_reg(r2, r1, islv ? VT_PTR : type.t);
vtop->r = r2;
}
gsym(tt);
}
@ -6745,6 +6758,7 @@ ST_FUNC void gexpr(void)
/* make builtin_constant_p((1,2)) return 0 (like on gcc) */
if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED)
if (vtop->type.t != VT_VOID && (vtop->type.t & VT_BTYPE) != VT_STRUCT)
gv(RC_TYPE(vtop->type.t));
}
}
@ -6855,11 +6869,10 @@ static void check_func_return(void)
{
if ((func_vt.t & VT_BTYPE) == VT_VOID)
return;
if (!strcmp (funcname, "main")
if ((!strcmp(funcname, "main") || func_old)
&& (func_vt.t & VT_BTYPE) == VT_INT) {
/* main returns 0 by default */
vpushi(0);
gen_assign_cast(&func_vt);
gfunc_return(&func_vt);
} else {
tcc_warning("function might return no value: '%s'", funcname);
@ -7242,6 +7255,8 @@ again:
tcc_warning("void function returns a value");
vtop--;
}
} else if (b && func_old && (func_vt.t & VT_BTYPE) == VT_INT) {
vpushi(0);
} else if (b) {
tcc_warning("'return' with no value");
b = 0;
@ -7806,21 +7821,12 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
ptr = sec->data + c;
val = vtop->c.i;
/* XXX: make code faster ? */
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) &&
vtop->sym->v >= SYM_FIRST_ANOM &&
/* XXX This rejects compound literals like
'(void *){ptr}'. The problem is that '&sym' is
represented the same way, which would be ruled out
by the SYM_FIRST_ANOM check above, but also '"string"'
in 'char *p = "string"' is represented the same
with the type being VT_PTR and the symbol being an
anonymous one. That is, there's no difference in vtop
between '(void *){x}' and '&(void *){x}'. Ignore
pointer typed entities here. Hopefully no real code
will ever use compound literals with scalar type. */
(vtop->type.t & VT_BTYPE) != VT_PTR) {
/* These come from compound literals, memcpy stuff over. */
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)
&& vtop->sym->v >= SYM_FIRST_ANOM
&& ((vtop->r & VT_LVAL) /* compound literal */
|| bt == VT_STRUCT /* designator */
)) {
/* memcpy stuff over. */
Section *ssec;
ElfSym *esym;
ElfW_Rel *rel;
@ -8072,6 +8078,8 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
}
}
}
if (tok == ',' && !no_oblock) /* static const char s[] = { "123", }; */
next();
} else {
do_init_array:
@ -8528,6 +8536,7 @@ static void gen_function(Sym *sym)
func_ind = ind;
func_vt = sym->type.ref->type;
func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS;
func_old = sym->type.ref->f.func_type == FUNC_OLD;
/* NOTE: we patch the symbol size later */
put_extern_sym(sym, cur_text_section, ind, 0);

View File

@ -702,7 +702,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
if (sym->st_shndx == SHN_UNDEF)
tcc_error("undefined local symbo: '%s'",
tcc_error("unresolved local reference to '%s'",
(char *) symtab_section->link->data + sym->st_name);
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
} else {
@ -859,7 +859,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
if (sym->st_shndx == SHN_UNDEF)
tcc_error("undefined local symbo: '%s'",
tcc_error("unresolved local reference to '%s'",
(char *) symtab_section->link->data + sym->st_name);
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
} else {
@ -1042,7 +1042,7 @@ static int check_symbols(TCCState *s1, struct macho *mo)
sym->st_shndx = SHN_FROMDLL;
continue;
}
tcc_error_noabort("undefined symbol '%s'", name);
tcc_error_noabort("unresolved reference to '%s'", name);
ret = -1;
}
}

30
tccpp.c
View File

@ -987,11 +987,7 @@ static inline int tok_size(const int *p)
case TOK_CULLONG:
return 1 + 2;
case TOK_CLDOUBLE:
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
return 1 + 8 / 4;
#else
return 1 + LDOUBLE_SIZE / 4;
#endif
return 1 + LDOUBLE_WORDS;
default:
return 1 + 0;
}
@ -1130,22 +1126,12 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
str[len++] = cv->tab[1];
break;
case TOK_CLDOUBLE:
#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
#elif LDOUBLE_SIZE == 12
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
str[len++] = cv->tab[2];
#elif LDOUBLE_SIZE == 16
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
if (LDOUBLE_WORDS >= 3)
str[len++] = cv->tab[2];
if (LDOUBLE_WORDS >= 4)
str[len++] = cv->tab[3];
#else
#error add long double size support
#endif
break;
default:
break;
}
@ -1219,15 +1205,7 @@ static inline void tok_get(int *t, const int **pp, CValue *cv)
n = 2;
goto copy;
case TOK_CLDOUBLE:
#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE
n = 2;
#elif LDOUBLE_SIZE == 12
n = 3;
#elif LDOUBLE_SIZE == 16
n = 4;
#else
# error add long double size support
#endif
n = LDOUBLE_WORDS;
copy:
do
*tab++ = *p++;

View File

@ -1465,17 +1465,37 @@ 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; /* a global variable can be defined several times without error ! */
int cinit1;
int cinit1 = 0;
int *cinit2 = (int []){3, 2, 1};
uintptr_t cinit3 = (uintptr_t)"AA";
char const * const cinit8[] = { [0 ... 1] = "BB", [2 ... 4] = "CC" };
void *cinit52 = &(void*){ (void*) 52 };
#if __TINYC__ || __GNUC__ >= 6
int cinit4 = (int){44};
void *cinit51 = (void*){ (void*) 51 };
struct _c6 { int a,b; } cinit6 = (struct _c6){61,62}, *cinit7 = &(struct _c6){71,72};
#else
int cinit4 = 44;
void *cinit51 = (void*)51;
struct _c6 { int a,b; } cinit6 = { 61,62 }, cinit70 = {71,72}, *cinit7 = &cinit70;
#endif
void compound_literal_test(void)
{
int *p, i;
char *q, *q3;
printf("cinit3 : %s\n", cinit3);
printf("cinit4 : %d\n", cinit4);
printf("cinit51 : %d\n", (int)cinit51);
printf("cinit52 : %d\n", *(int*)cinit52);
printf("cinit6 : %d %d\n", cinit6.a, cinit6.b);
printf("cinit7 : %d %d\n", cinit7->a, cinit7->b);
printf("cinit8 : %s %s %s %s %s\n", cinit8[0], cinit8[1], cinit8[2], cinit8[3], cinit8[4]);
p = (int []){1, 2, 3};
for(i=0;i<3;i++)
printf(" %d", p[i]);

View File

@ -421,7 +421,7 @@ int f() { return v(); }
#elif defined test_switch_W4
#pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror")
#endif
void func()
void func(void)
{
char *ccp = "123";
fink();

View File

@ -314,7 +314,7 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got)
}
} else if ((r & VT_VALMASK) == VT_LOCAL) {
/* currently, we use only ebp as base */
if (c == (char)c) {
if (c == (signed char)c) {
/* short reference */
o(0x45 | op_reg);
g(c);
@ -436,8 +436,7 @@ void load(int r, SValue *sv)
b = 0xdb, r = 5; /* fldt */
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
b = 0xbe0f; /* movsbl */
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED) ||
(ft & VT_TYPE) == (VT_BOOL | VT_UNSIGNED)) {
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
b = 0xb60f; /* movzbl */
} else if ((ft & VT_TYPE) == VT_SHORT) {
b = 0xbf0f; /* movswl */
@ -532,7 +531,6 @@ void load(int r, SValue *sv)
o(0x44 + REG_VALUE(r)*8); /* %xmmN */
o(0xf024);
} else {
if (!nocode_wanted)
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
if ((ft & VT_BTYPE) == VT_FLOAT) {
o(0x100ff3);
@ -543,7 +541,6 @@ void load(int r, SValue *sv)
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
}
} else if (r == TREG_ST0) {
if (!nocode_wanted)
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
/* gen_cvt_ftof(VT_LDOUBLE); */
/* movsd %xmmN,-0x10(%rsp) */
@ -749,7 +746,7 @@ static int arg_prepare_reg(int idx) {
static void gen_offs_sp(int b, int r, int d)
{
orex(1,0,r & 0x100 ? 0 : r, b);
if (d == (char)d) {
if (d == (signed char)d) {
o(0x2444 | (REG_VALUE(r) << 3));
g(d);
} else {
@ -1052,7 +1049,7 @@ void gfunc_epilog(void)
static void gadd_sp(int val)
{
if (val == (char)val) {
if (val == (signed char)val) {
o(0xc48348);
g(val);
} else {
@ -1635,7 +1632,7 @@ void gjmp_addr(int a)
{
int r;
r = a - ind - 2;
if (r == (char)r) {
if (r == (signed char)r) {
g(0xeb);
g(r);
} else {
@ -1704,7 +1701,7 @@ void gen_opi(int op)
r = gv(RC_INT);
vswap();
c = vtop->c.i;
if (c == (char)c) {
if (c == (signed char)c) {
/* XXX: generate inc and dec for smaller code ? */
orex(ll, r, 0, 0x83);
o(0xc0 | (opc << 3) | REG_VALUE(r));