From 7e01b203628273545644a4da4cc00284c81ab722 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 10 Jan 2026 21:51:08 +0100 Subject: [PATCH] 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 --- arm-gen.c | 3 +- arm64-gen.c | 71 +++++++++++------------- i386-gen.c | 10 ++-- include/tccdefs.h | 14 +++-- libtcc.c | 6 +-- tcc.c | 16 +++--- tcc.h | 9 ++-- tccasm.c | 17 +++--- tccelf.c | 8 +-- tccgen.c | 77 +++++++++++++++------------ tccmacho.c | 6 +-- tccpp.c | 30 ++--------- tests/tcctest.c | 24 ++++++++- tests/tests2/60_errors_and_warnings.c | 2 +- x86_64-gen.c | 19 +++---- 15 files changed, 161 insertions(+), 151 deletions(-) diff --git a/arm-gen.c b/arm-gen.c index 81fa185a..51a4b7d6 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -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 diff --git a/arm64-gen.c b/arm64-gen.c index 9157a9d2..ab6a4a6b 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -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; diff --git a/i386-gen.c b/i386-gen.c index 512a6c7c..e46a9718 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -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 == '+'); diff --git a/include/tccdefs.h b/include/tccdefs.h index 57d1380a..2655c1dd 100644 --- a/include/tccdefs.h +++ b/include/tccdefs.h @@ -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 diff --git a/libtcc.c b/libtcc.c index 9fd92e2d..80a1a8fa 100644 --- a/libtcc.c +++ b/libtcc.c @@ -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) diff --git a/tcc.c b/tcc.c index e59d8fbb..f68ca9c8 100644 --- a/tcc.c +++ b/tcc.c @@ -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(); diff --git a/tcc.h b/tcc.h index ed821cce..8b8c8b1b 100644 --- a/tcc.h +++ b/tcc.h @@ -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); diff --git a/tccasm.c b/tccasm.c index b415f606..eb24e3a0 100644 --- a/tccasm.c +++ b/tccasm.c @@ -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; } diff --git a/tccelf.c b/tccelf.c index 122295d1..9c7e6fcc 100644 --- a/tccelf.c +++ b/tccelf.c @@ -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; diff --git a/tccgen.c b/tccgen.c index 5848d9e0..c5118dd7 100644 --- a/tccgen.c +++ b/tccgen.c @@ -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,7 +6691,8 @@ static void expr_cond(void) tt = r2 = 0; if (c < 0) { - r2 = gv(rc); + if (type.t != VT_VOID) + r2 = gv(rc); tt = gjmp(0); } gsym(u); @@ -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) { - r1 = gv(rc); - move_reg(r2, r1, islv ? VT_PTR : type.t); - vtop->r = r2; + if (type.t != VT_VOID) { + r1 = gv(rc); + move_reg(r2, r1, islv ? VT_PTR : type.t); + vtop->r = r2; + } gsym(tt); } @@ -6745,7 +6758,8 @@ 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) - gv(RC_TYPE(vtop->type.t)); + 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); diff --git a/tccmacho.c b/tccmacho.c index 2661f929..e4f2097c 100644 --- a/tccmacho.c +++ b/tccmacho.c @@ -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; } } diff --git a/tccpp.c b/tccpp.c index 4dd0bb53..21bfc0e3 100644 --- a/tccpp.c +++ b/tccpp.c @@ -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++; diff --git a/tests/tcctest.c b/tests/tcctest.c index 0bb392e4..0f55710d 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -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]); diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index b89d7343..2b8489d6 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -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(); diff --git a/x86_64-gen.c b/x86_64-gen.c index 06eb90c0..1cb532f8 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -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,8 +531,7 @@ 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)); + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); if ((ft & VT_BTYPE) == VT_FLOAT) { o(0x100ff3); } else { @@ -543,8 +541,7 @@ 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)); + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); /* gen_cvt_ftof(VT_LDOUBLE); */ /* movsd %xmmN,-0x10(%rsp) */ o(0x110ff2); @@ -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));