From 1443039416dd02750765efde1af35e31c8d41be3 Mon Sep 17 00:00:00 2001 From: grischka Date: Sun, 24 Sep 2017 18:57:48 +0200 Subject: [PATCH] 'long' review add some features for more complete 'long' support tcc.h: - use LONG_SIZE=4/8 instead of TCC_LONG_ARE_64_BIT tccgen.c: - add ptrdiff_type, update size_type - support shift and ?: operations - support long enum types - display 'long' from type_to_str - nwchar_t is unsigned short on windows - unrelated: use memcpy in init_putv for long doubles to avoid random bytes in the image (if tcc was compiled by gcc) for diff purposes. tccpp.c: - make parse_number return correct types - improve multi-character-constants 'XX' 'abcd' Changelog: - update --- Changelog | 6 +- libtcc.c | 14 ++--- tcc.h | 23 ++++--- tccgen.c | 173 +++++++++++++++++++++++++--------------------------- tccpp.c | 122 ++++++++++++++++++------------------ win32/build-tcc.bat | 2 +- 6 files changed, 164 insertions(+), 176 deletions(-) diff --git a/Changelog b/Changelog index 2ab33744..17f5bded 100644 --- a/Changelog +++ b/Changelog @@ -9,11 +9,10 @@ User interface: - -mno-sse on x86-64 disables use of SSE instructions - @listfile support (Vlad Vissoultchev) - tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka) -- CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH environment variables support +- CPATH, C_INCLUDE_PATH and LIBRARY_PATH environment variables support (Andrew Aladjev, Urs Janssen) Platforms: -- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien) - new AARCH64 (arm64) target (Edmund Grimley Evans) - vastly improved support for ARM hard float calling convention (Thomas Preud'homme, Daniel Glöckner) @@ -22,6 +21,7 @@ Platforms: - ABI tests with native compiler using libtcc (James Lyon) - UNICODE startup code supports wmain and wWinMain (YX Hao) - shared libraries for x86_64 (Michael Matz) +- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien) Features: - VLA (variable length array) improved (James Lyon, Pip Cet) @@ -35,6 +35,8 @@ Features: - standard conforming (and GCC compatible) struct initialization (Michael Matz) - bit-field layout made compatible with GCC (Michael Matz) +- UTF8 in string literals supported (Zdenek Pavlas) +_ _Generic(...) supported (Matthias Gatto) Licensing: - TinyCC partly relicensed to MIT license (See RELICENSING file). diff --git a/libtcc.c b/libtcc.c index 6a5e4527..41c814d8 100644 --- a/libtcc.c +++ b/libtcc.c @@ -836,21 +836,21 @@ LIBTCCAPI TCCState *tcc_new(void) # endif /* TinyCC & gcc defines */ -#if defined(TCC_TARGET_PE) && PTR_SIZE == 8 +#if PTR_SIZE == 4 + /* 32bit systems. */ + tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); + tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); + tcc_define_symbol(s, "__ILP32__", NULL); +#elif LONG_SIZE == 4 /* 64bit Windows. */ tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long"); tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long"); tcc_define_symbol(s, "__LLP64__", NULL); -#elif PTR_SIZE == 8 +#else /* Other 64bit systems. */ tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long"); tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long"); tcc_define_symbol(s, "__LP64__", NULL); -#else - /* Other 32bit systems. */ - tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); - tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); - tcc_define_symbol(s, "__ILP32__", NULL); #endif #if defined(TCC_MUSL) diff --git a/tcc.h b/tcc.h index bfe6ab43..06965ebf 100644 --- a/tcc.h +++ b/tcc.h @@ -361,6 +361,12 @@ extern long double strtold (const char *__nptr, char **__endptr); /* target address type */ #define addr_t ElfW(Addr) +#if PTR_SIZE == 8 && !defined TCC_TARGET_PE +# define LONG_SIZE 8 +#else +# define LONG_SIZE 4 +#endif + /* -------------------------------------------- */ #define INCLUDE_STACK_SIZE 32 @@ -880,14 +886,14 @@ struct filespec { #define VT_CONSTANT 0x0100 /* const modifier */ #define VT_VOLATILE 0x0200 /* volatile modifier */ #define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */ -#define VT_LONG 0x0800 +#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */ /* storage */ #define VT_EXTERN 0x00001000 /* extern definition */ #define VT_STATIC 0x00002000 /* static variable */ #define VT_TYPEDEF 0x00004000 /* typedef definition */ #define VT_INLINE 0x00008000 /* inline definition */ -/* currently unused: 0x0800, 0x000[1248]0000 */ +/* currently unused: 0x000[1248]0000 */ #define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */ #define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD) @@ -906,7 +912,6 @@ struct filespec { #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) - /* token values */ /* warning: the following compare tokens depend on i386 asm code */ @@ -947,6 +952,7 @@ struct filespec { #define TOK_PPNUM 0xbe /* preprocessor number */ #define TOK_PPSTR 0xbf /* preprocessor string */ #define TOK_LINENUM 0xc0 /* line number info */ +#define TOK_TWODOTS 0xa8 /* C++ token ? */ /* <-- */ #define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ @@ -961,15 +967,8 @@ struct filespec { #define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */ #define TOK_NOSUBST 0xcc /* means following token has already been pp'd */ #define TOK_PPJOIN 0xcd /* A '##' in the right position to mean pasting */ - -#define TOK_CLONG 0xce /* long constant */ -#define TOK_CULONG 0xcf /* unsigned long constant */ - - -#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE - #define TCC_LONG_ARE_64_BIT -#endif - +#define TOK_CLONG 0xce /* long constant */ +#define TOK_CULONG 0xcf /* unsigned long constant */ #define TOK_SHL 0x01 /* shift left */ #define TOK_SAR 0x02 /* signed shift right */ diff --git a/tccgen.c b/tccgen.c index 3da1143a..e6a56a7b 100644 --- a/tccgen.c +++ b/tccgen.c @@ -61,7 +61,7 @@ ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc ST_DATA const char *funcname; ST_DATA int g_debug; -ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; +ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type; ST_DATA struct switch_t { struct case_t { @@ -240,9 +240,14 @@ ST_FUNC int tccgen_compile(TCCState *s1) char_pointer_type.t = VT_BYTE; mk_pointer(&char_pointer_type); #if PTR_SIZE == 4 - size_type.t = VT_INT; + size_type.t = VT_INT | VT_UNSIGNED; + ptrdiff_type.t = VT_INT; +#elif LONG_SIZE == 4 + size_type.t = VT_LLONG | VT_UNSIGNED; + ptrdiff_type.t = VT_LLONG; #else - size_type.t = VT_LLONG; + size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED; + ptrdiff_type.t = VT_LONG | VT_LLONG; #endif func_old_type.t = VT_FUNC; func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); @@ -2127,12 +2132,7 @@ redo: } vrott(3); gen_opic(op); - /* set to integer type */ -#if PTR_SIZE == 8 - vtop->type.t = VT_LLONG; -#else - vtop->type.t = VT_INT; -#endif + vtop->type.t = ptrdiff_type.t; vswap(); gen_op(TOK_PDIV); } else { @@ -2218,14 +2218,15 @@ redo: t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) t |= VT_UNSIGNED; + t |= (VT_LONG & t1); goto std_op; } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { /* cast to biggest op */ - t = VT_LLONG; - /* check if we need to keep type as long or as long long */ - if ((t1 & VT_LONG && (t2 & (VT_BTYPE | VT_LONG)) != VT_LLONG) || - (t2 & VT_LONG && (t1 & (VT_BTYPE | VT_LONG)) != VT_LLONG)) - t |= VT_LONG; + t = VT_LLONG | VT_LONG; + if (bt1 == VT_LLONG) + t &= t1; + if (bt2 == VT_LLONG) + 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)) @@ -2233,12 +2234,8 @@ redo: goto std_op; } else { /* integer operations */ - t = VT_INT; - - if ((t1 & VT_LONG) || (t2 & VT_LONG)) - t |= VT_LONG; - - /* convert to unsigned if it does not fit in an integer */ + 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)) t |= VT_UNSIGNED; @@ -2741,7 +2738,6 @@ static int compare_types(CType *type1, CType *type2, int unqualified) t1 &= ~VT_DEFSIGN; t2 &= ~VT_DEFSIGN; } - /* XXX: bitfields ? */ if (t1 != t2) return 0; @@ -2790,14 +2786,7 @@ static void type_to_str(char *buf, int buf_size, t = type->t; bt = t & VT_BTYPE; buf[0] = '\0'; - if (t & VT_CONSTANT) - pstrcat(buf, buf_size, "const "); - if (t & VT_VOLATILE) - pstrcat(buf, buf_size, "volatile "); - if ((t & (VT_DEFSIGN | VT_UNSIGNED)) == (VT_DEFSIGN | VT_UNSIGNED)) - pstrcat(buf, buf_size, "unsigned "); - else if (t & VT_DEFSIGN) - pstrcat(buf, buf_size, "signed "); + if (t & VT_EXTERN) pstrcat(buf, buf_size, "extern "); if (t & VT_STATIC) @@ -2806,17 +2795,20 @@ static void type_to_str(char *buf, int buf_size, pstrcat(buf, buf_size, "typedef "); if (t & VT_INLINE) pstrcat(buf, buf_size, "inline "); + if (t & VT_VOLATILE) + pstrcat(buf, buf_size, "volatile "); + if (t & VT_CONSTANT) + pstrcat(buf, buf_size, "const "); + + if (((t & VT_DEFSIGN) && bt == VT_BYTE) + || ((t & VT_UNSIGNED) + && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG) + && !IS_ENUM(t) + )) + pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed "); + buf_size -= strlen(buf); buf += strlen(buf); - if (IS_ENUM(t)) { - tstr = "enum "; - goto tstruct; - } - - if (!bt && VT_LONG & t) { - tstr = "long"; - goto add_tstr; - } switch(bt) { case VT_VOID: @@ -2833,10 +2825,16 @@ static void type_to_str(char *buf, int buf_size, goto add_tstr; case VT_INT: tstr = "int"; - goto add_tstr; + goto maybe_long; case VT_LLONG: tstr = "long long"; - goto add_tstr; + maybe_long: + if (t & VT_LONG) + tstr = "long"; + if (!IS_ENUM(t)) + goto add_tstr; + tstr = "enum "; + goto tstruct; case VT_FLOAT: tstr = "float"; goto add_tstr; @@ -2902,7 +2900,7 @@ static void type_to_str(char *buf, int buf_size, casts if needed. */ static void gen_assign_cast(CType *dt) { - CType *st, *type1, *type2, tmp_type1, tmp_type2; + CType *st, *type1, *type2; char buf1[256], buf2[256]; int dbt, sbt; @@ -2958,7 +2956,7 @@ static void gen_assign_cast(CType *dt) in pointer target signedness. Do warn for different base types, though, in particular for unsigned enums and signed int targets. */ - if ((type1->t & VT_BTYPE) != (type2->t & VT_BTYPE) + if ((type1->t & (VT_BTYPE|VT_LONG)) != (type2->t & (VT_BTYPE|VT_LONG)) || IS_ENUM(type1->t) || IS_ENUM(type2->t) ) tcc_warning("assignment from incompatible pointer type"); @@ -2982,11 +2980,7 @@ static void gen_assign_cast(CType *dt) break; case VT_STRUCT: case_VT_STRUCT: - tmp_type1 = *dt; - tmp_type2 = *st; - tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); - tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); - if (!is_compatible_types(&tmp_type1, &tmp_type2)) { + if (!is_compatible_unqualified_types(dt, st)) { error: type_to_str(buf1, sizeof(buf1), st, NULL); type_to_str(buf2, sizeof(buf2), dt, NULL); @@ -3775,10 +3769,10 @@ do_decl: t.t = VT_INT; if (nl >= 0) { if (pl != (unsigned)pl) - t.t = VT_LLONG; + t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); t.t |= VT_UNSIGNED; } else if (pl != (int)pl || nl != (int)nl) - t.t = VT_LLONG; + t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); s->type.t = type->t = t.t | VT_ENUM; s->c = 0; /* set type for enum members */ @@ -3791,7 +3785,8 @@ do_decl: if (ll == (unsigned)ll) continue; } - ss->type.t = (ss->type.t & ~VT_BTYPE) | VT_LLONG; + ss->type.t = (ss->type.t & ~VT_BTYPE) + | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); } } else { c = 0; @@ -3964,7 +3959,7 @@ static int parse_btype(CType *type, AttributeDef *ad) bt = u; } if (u != VT_INT) - t = (t & ~VT_BTYPE) | u; + t = (t & ~(VT_BTYPE|VT_LONG)) | u; typespec_found = 1; break; case TOK_VOID: @@ -3978,11 +3973,9 @@ static int parse_btype(CType *type, AttributeDef *ad) goto basic_type; case TOK_LONG: if ((t & VT_BTYPE) == VT_DOUBLE) { -#ifndef TCC_TARGET_PE - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE; -#endif - } else if (t & VT_LONG) { - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LLONG; + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; + } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG; } else { u = VT_LONG; goto basic_type; @@ -4003,12 +3996,8 @@ static int parse_btype(CType *type, AttributeDef *ad) u = VT_FLOAT; goto basic_type; case TOK_DOUBLE: - if (t & VT_LONG) { -#ifdef TCC_TARGET_PE - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_DOUBLE; -#else - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE; -#endif + if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; } else { u = VT_DOUBLE; goto basic_type; @@ -4098,7 +4087,7 @@ static int parse_btype(CType *type, AttributeDef *ad) parse_attribute(ad); if (ad->attr_mode) { u = ad->attr_mode -1; - t = (t & ~VT_BTYPE) | u; + t = (t & ~(VT_BTYPE|VT_LONG)) | u; } break; /* GNUC typeof */ @@ -4118,7 +4107,7 @@ static int parse_btype(CType *type, AttributeDef *ad) s = sym_find(tok); if (!s || !(s->type.t & VT_TYPEDEF)) goto the_end; - t &= ~VT_BTYPE; + t &= ~(VT_BTYPE|VT_LONG); u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; type->t = (s->type.t & ~VT_TYPEDEF) | u; type->ref = s->type.ref; @@ -4139,13 +4128,13 @@ the_end: if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) t |= VT_UNSIGNED; } - - /* long is never used as type */ - if (t & VT_LONG) -#if PTR_SIZE == 8 && !defined TCC_TARGET_PE - t = (t & ~VT_BTYPE) | VT_LLONG; -#else - t = (t & ~VT_BTYPE) | VT_INT; + /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */ + bt = t & (VT_BTYPE|VT_LONG); + if (bt == VT_LONG) + t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT; +#ifdef TCC_TARGET_PE + if (bt == VT_LDOUBLE) + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE; #endif type->t = t; return type_found; @@ -4544,9 +4533,13 @@ ST_FUNC void unary(void) case TOK_EXTENSION: next(); goto tok_next; + case TOK_LCHAR: +#ifdef TCC_TARGET_PE + t = VT_SHORT|VT_UNSIGNED; + goto push_tokc; +#endif case TOK_CINT: case TOK_CCHAR: - case TOK_LCHAR: t = VT_INT; push_tokc: type.t = t; @@ -4572,14 +4565,10 @@ ST_FUNC void unary(void) t = VT_LDOUBLE; goto push_tokc; case TOK_CLONG: + t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG; + goto push_tokc; case TOK_CULONG: - #ifdef TCC_LONG_ARE_64_BIT - t = VT_LLONG | VT_LONG; - #else - t = VT_INT | VT_LONG; - #endif - if (tok == TOK_CULONG) - t |= VT_UNSIGNED; + t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED; goto push_tokc; case TOK___FUNCTION__: if (!gnu_ext) @@ -5491,7 +5480,11 @@ static void expr_cond(void) } } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { /* cast to biggest op */ - type.t = VT_LLONG; + type.t = VT_LLONG | VT_LONG; + if (bt1 == VT_LLONG) + type.t &= t1; + 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)) @@ -5518,7 +5511,7 @@ static void expr_cond(void) type.t = VT_VOID; } else { /* integer operations */ - type.t = VT_INT; + 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)) @@ -6490,20 +6483,20 @@ static void init_putv(CType *type, Section *sec, unsigned long c) *(double *)ptr = vtop->c.d; break; case VT_LDOUBLE: - if (sizeof(long double) == LDOUBLE_SIZE) - *(long double *)ptr = vtop->c.ld; - else if (sizeof(double) == LDOUBLE_SIZE) - *(double *)ptr = (double)vtop->c.ld; #if (defined __i386__ || defined __x86_64__) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) - else if (sizeof (long double) >= 10) - memcpy(memset(ptr, 0, LDOUBLE_SIZE), &vtop->c.ld, 10); + if (sizeof (long double) >= 10) /* zero pad ten-byte LD */ + memcpy(ptr, &vtop->c.ld, 10); #ifdef __TINYC__ else if (sizeof (long double) == sizeof (double)) - __asm__("fldl %1\nfstpt %0\n" : "=m" - (memset(ptr, 0, LDOUBLE_SIZE), ptr) : "m" (vtop->c.ld)); + __asm__("fldl %1\nfstpt %0\n" : "=m" (ptr) : "m" (vtop->c.ld)); #endif + else #endif - else + if (sizeof(long double) == LDOUBLE_SIZE) + *(long double*)ptr = vtop->c.ld; + else if (sizeof(double) == LDOUBLE_SIZE) + *(double *)ptr = (double)vtop->c.ld; + else tcc_error("can't cross compile long double constants"); break; #if PTR_SIZE != 8 diff --git a/tccpp.c b/tccpp.c index e43cb233..7561b363 100644 --- a/tccpp.c +++ b/tccpp.c @@ -89,7 +89,7 @@ static const unsigned char tok_two_chars[] = '^','=', TOK_A_XOR, '|','=', TOK_A_OR, '-','>', TOK_ARROW, - '.','.', 0xa8, // C++ token ? + '.','.', TOK_TWODOTS, '#','#', TOK_TWOSHARPS, 0 }; @@ -1017,23 +1017,18 @@ static inline int tok_size(const int *p) case TOK_LCHAR: case TOK_CFLOAT: case TOK_LINENUM: -#ifndef TCC_LONG_ARE_64_BIT - case TOK_CLONG; - case TOK_CULONG; -#endif return 1 + 1; case TOK_STR: case TOK_LSTR: case TOK_PPNUM: case TOK_PPSTR: return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2); + case TOK_CLONG: + case TOK_CULONG: + return 1 + LONG_SIZE / 4; case TOK_CDOUBLE: case TOK_CLLONG: case TOK_CULLONG: -#ifdef TCC_LONG_ARE_64_BIT - case TOK_CLONG; - case TOK_CULONG; -#endif return 1 + 2; case TOK_CLDOUBLE: return 1 + LDOUBLE_SIZE / 4; @@ -1149,7 +1144,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv) case TOK_LCHAR: case TOK_CFLOAT: case TOK_LINENUM: -#ifndef TCC_LONG_ARE_64_BIT +#if LONG_SIZE == 4 case TOK_CLONG: case TOK_CULONG: #endif @@ -1173,7 +1168,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv) case TOK_CDOUBLE: case TOK_CLLONG: case TOK_CULLONG: -#ifdef TCC_LONG_ARE_64_BIT +#if LONG_SIZE == 8 case TOK_CLONG: case TOK_CULONG: #endif @@ -1227,17 +1222,20 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv) tab = cv->tab; switch(*t = *p++) { +#if LONG_SIZE == 4 + case TOK_CLONG: +#endif case TOK_CINT: - case TOK_CUINT: case TOK_CCHAR: case TOK_LCHAR: case TOK_LINENUM: -#ifndef TCC_LONG_ARE_64_BIT - case TOK_CLONG: + cv->i = *p++; + break; +#if LONG_SIZE == 4 case TOK_CULONG: #endif - tab[0] = *p++; - cv->i = (*t == TOK_CUINT) ? (unsigned)cv->i : (int)cv->i; + case TOK_CUINT: + cv->i = (unsigned)*p++; break; case TOK_CFLOAT: tab[0] = *p++; @@ -1253,7 +1251,7 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv) case TOK_CDOUBLE: case TOK_CLLONG: case TOK_CULLONG: -#ifdef TCC_LONG_ARE_64_BIT +#if LONG_SIZE == 8 case TOK_CLONG: case TOK_CULONG: #endif @@ -2206,23 +2204,24 @@ static void parse_string(const char *s, int len) tcc_free(p); if (sep == '\'') { - int char_size; + int char_size, i, n, c; /* XXX: make it portable */ if (!is_long) - char_size = 1; + tok = TOK_CCHAR, char_size = 1; else - char_size = sizeof(nwchar_t); - if (tokcstr.size <= char_size) + tok = TOK_LCHAR, char_size = sizeof(nwchar_t); + n = tokcstr.size / char_size - 1; + if (n < 1) tcc_error("empty character constant"); - if (tokcstr.size > 2 * char_size) + if (n > 1) tcc_warning("multi-character character constant"); - if (!is_long) { - tokc.i = *(int8_t *)tokcstr.data; - tok = TOK_CCHAR; - } else { - tokc.i = *(nwchar_t *)tokcstr.data; - tok = TOK_LCHAR; + for (c = i = 0; i < n; ++i) { + if (is_long) + c = ((nwchar_t *)tokcstr.data)[i]; + else + c = (c << 8) | ((char *)tokcstr.data)[i]; } + tokc.i = c; } else { tokc.str.size = tokcstr.size; tokc.str.data = tokcstr.data; @@ -2456,7 +2455,7 @@ static void parse_number(const char *p) } } else { unsigned long long n, n1; - int lcount, ucount, must_64bit; + int lcount, ucount, ov = 0; const char *p1; /* integer number */ @@ -2483,14 +2482,13 @@ static void parse_number(const char *p) n1 = n; n = n * b + t; /* detect overflow */ - /* XXX: this test is not reliable */ - if (n < n1) - tcc_error("integer constant overflow"); + if (n1 >= 0x1000000000000000ULL && n / b != n1) + ov = 1; } /* Determine the characteristics (unsigned and/or 64bit) the type of the constant must have according to the constant suffix(es) */ - lcount = ucount = must_64bit = 0; + lcount = ucount = 0; p1 = p; for(;;) { t = toup(ch); @@ -2500,8 +2498,6 @@ static void parse_number(const char *p) if (lcount && *(p - 1) != ch) tcc_error("incorrect integer suffix: %s", p1); lcount++; - if (lcount == 2) - must_64bit = 1; ch = *p++; } else if (t == 'U') { if (ucount >= 1) @@ -2513,38 +2509,36 @@ static void parse_number(const char *p) } } - /* Whether 64 bits are needed to hold the constant's value */ - if (n & 0xffffffff00000000LL || must_64bit) { - tok = TOK_CLLONG; - n1 = n >> 32; - } else if (lcount) { -#ifdef TCC_LONG_ARE_64_BIT - n1 = n >> 32; -#else - n1 = n; -#endif - tok = TOK_CLONG; - } else { - tok = TOK_CINT; - n1 = n; + /* Determine if it needs 64 bits and/or unsigned in order to fit */ + if (ucount == 0 && b == 10) { + if (lcount <= (LONG_SIZE == 4)) { + if (n >= 0x80000000U) + lcount = (LONG_SIZE == 4) + 1; + } + if (n >= 0x8000000000000000ULL) + ov = 1, ucount = 1; + } else { + if (lcount <= (LONG_SIZE == 4)) { + if (n >= 0x100000000ULL) + lcount = (LONG_SIZE == 4) + 1; + else if (n >= 0x80000000U) + ucount = 1; + } + if (n >= 0x8000000000000000ULL) + ucount = 1; } - /* Whether type must be unsigned to hold the constant's value */ - if (ucount || ((n1 >> 31) && (b != 10))) { - if (tok == TOK_CLLONG) - tok = TOK_CULLONG; - else if (tok == TOK_CLONG) - tok = TOK_CULONG; - else - tok = TOK_CUINT; - /* If decimal and no unsigned suffix, bump to 64 bits or throw error */ - } else if (n1 >> 31) { - if (tok == TOK_CINT) - tok = TOK_CLLONG; - else - tcc_error("integer constant overflow"); - } + if (ov) + tcc_warning("integer constant overflow"); + tok = TOK_CINT; + if (lcount) { + tok = TOK_CLONG; + if (lcount == 2) + tok = TOK_CLLONG; + } + if (ucount) + ++tok; /* TOK_CU... */ tokc.i = n; } if (ch) diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index b234178a..3c3a7267 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -113,7 +113,7 @@ for %%f in (*tcc.exe *tcc.dll) do @del %%f :compiler %CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL @if errorlevel 1 goto :the_end -%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE=0 +%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0" %CC% -o %PX%-tcc.exe ..\tcc.c %DX% @if (%TCC_FILES%)==(no) goto :files-done -- 2.11.4.GIT