'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
master
grischka 2017-09-24 18:57:48 +02:00
parent 870271ea07
commit 1443039416
6 changed files with 164 additions and 176 deletions

View File

@ -9,11 +9,10 @@ User interface:
- -mno-sse on x86-64 disables use of SSE instructions - -mno-sse on x86-64 disables use of SSE instructions
- @listfile support (Vlad Vissoultchev) - @listfile support (Vlad Vissoultchev)
- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka) - 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) (Andrew Aladjev, Urs Janssen)
Platforms: Platforms:
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
- new AARCH64 (arm64) target (Edmund Grimley Evans) - new AARCH64 (arm64) target (Edmund Grimley Evans)
- vastly improved support for ARM hard float calling convention - vastly improved support for ARM hard float calling convention
(Thomas Preud'homme, Daniel Glöckner) (Thomas Preud'homme, Daniel Glöckner)
@ -22,6 +21,7 @@ Platforms:
- ABI tests with native compiler using libtcc (James Lyon) - ABI tests with native compiler using libtcc (James Lyon)
- UNICODE startup code supports wmain and wWinMain (YX Hao) - UNICODE startup code supports wmain and wWinMain (YX Hao)
- shared libraries for x86_64 (Michael Matz) - shared libraries for x86_64 (Michael Matz)
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
Features: Features:
- VLA (variable length array) improved (James Lyon, Pip Cet) - VLA (variable length array) improved (James Lyon, Pip Cet)
@ -35,6 +35,8 @@ Features:
- standard conforming (and GCC compatible) struct initialization - standard conforming (and GCC compatible) struct initialization
(Michael Matz) (Michael Matz)
- bit-field layout made compatible with GCC (Michael Matz) - bit-field layout made compatible with GCC (Michael Matz)
- UTF8 in string literals supported (Zdenek Pavlas)
_ _Generic(...) supported (Matthias Gatto)
Licensing: Licensing:
- TinyCC partly relicensed to MIT license (See RELICENSING file). - TinyCC partly relicensed to MIT license (See RELICENSING file).

View File

@ -836,21 +836,21 @@ LIBTCCAPI TCCState *tcc_new(void)
# endif # endif
/* TinyCC & gcc defines */ /* 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. */ /* 64bit Windows. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long"); tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long"); tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
tcc_define_symbol(s, "__LLP64__", NULL); tcc_define_symbol(s, "__LLP64__", NULL);
#elif PTR_SIZE == 8 #else
/* Other 64bit systems. */ /* Other 64bit systems. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long"); tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long"); tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
tcc_define_symbol(s, "__LP64__", NULL); 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 #endif
#if defined(TCC_MUSL) #if defined(TCC_MUSL)

23
tcc.h
View File

@ -361,6 +361,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* target address type */ /* target address type */
#define addr_t ElfW(Addr) #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 #define INCLUDE_STACK_SIZE 32
@ -880,14 +886,14 @@ struct filespec {
#define VT_CONSTANT 0x0100 /* const modifier */ #define VT_CONSTANT 0x0100 /* const modifier */
#define VT_VOLATILE 0x0200 /* volatile modifier */ #define VT_VOLATILE 0x0200 /* volatile modifier */
#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */ #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 */ /* storage */
#define VT_EXTERN 0x00001000 /* extern definition */ #define VT_EXTERN 0x00001000 /* extern definition */
#define VT_STATIC 0x00002000 /* static variable */ #define VT_STATIC 0x00002000 /* static variable */
#define VT_TYPEDEF 0x00004000 /* typedef definition */ #define VT_TYPEDEF 0x00004000 /* typedef definition */
#define VT_INLINE 0x00008000 /* inline 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_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD) #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_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
/* token values */ /* token values */
/* warning: the following compare tokens depend on i386 asm code */ /* warning: the following compare tokens depend on i386 asm code */
@ -947,6 +952,7 @@ struct filespec {
#define TOK_PPNUM 0xbe /* preprocessor number */ #define TOK_PPNUM 0xbe /* preprocessor number */
#define TOK_PPSTR 0xbf /* preprocessor string */ #define TOK_PPSTR 0xbf /* preprocessor string */
#define TOK_LINENUM 0xc0 /* line number info */ #define TOK_LINENUM 0xc0 /* line number info */
#define TOK_TWODOTS 0xa8 /* C++ token ? */
/* <-- */ /* <-- */
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ #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_PLCHLDR 0xcb /* placeholder token as defined in C99 */
#define TOK_NOSUBST 0xcc /* means following token has already been pp'd */ #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_PPJOIN 0xcd /* A '##' in the right position to mean pasting */
#define TOK_CLONG 0xce /* long constant */
#define TOK_CLONG 0xce /* long constant */ #define TOK_CULONG 0xcf /* unsigned 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_SHL 0x01 /* shift left */ #define TOK_SHL 0x01 /* shift left */
#define TOK_SAR 0x02 /* signed shift right */ #define TOK_SAR 0x02 /* signed shift right */

173
tccgen.c
View File

@ -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 const char *funcname;
ST_DATA int g_debug; 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 { ST_DATA struct switch_t {
struct case_t { struct case_t {
@ -240,9 +240,14 @@ ST_FUNC int tccgen_compile(TCCState *s1)
char_pointer_type.t = VT_BYTE; char_pointer_type.t = VT_BYTE;
mk_pointer(&char_pointer_type); mk_pointer(&char_pointer_type);
#if PTR_SIZE == 4 #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 #else
size_type.t = VT_LLONG; size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED;
ptrdiff_type.t = VT_LONG | VT_LLONG;
#endif #endif
func_old_type.t = VT_FUNC; func_old_type.t = VT_FUNC;
func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0);
@ -2127,12 +2132,7 @@ redo:
} }
vrott(3); vrott(3);
gen_opic(op); gen_opic(op);
/* set to integer type */ vtop->type.t = ptrdiff_type.t;
#if PTR_SIZE == 8
vtop->type.t = VT_LLONG;
#else
vtop->type.t = VT_INT;
#endif
vswap(); vswap();
gen_op(TOK_PDIV); gen_op(TOK_PDIV);
} else { } else {
@ -2218,14 +2218,15 @@ redo:
t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; t = bt1 == VT_LLONG ? VT_LLONG : VT_INT;
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED))
t |= VT_UNSIGNED; t |= VT_UNSIGNED;
t |= (VT_LONG & t1);
goto std_op; goto std_op;
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
/* cast to biggest op */ /* cast to biggest op */
t = VT_LLONG; t = VT_LLONG | VT_LONG;
/* check if we need to keep type as long or as long long */ if (bt1 == VT_LLONG)
if ((t1 & VT_LONG && (t2 & (VT_BTYPE | VT_LONG)) != VT_LLONG) || t &= t1;
(t2 & VT_LONG && (t1 & (VT_BTYPE | VT_LONG)) != VT_LLONG)) if (bt2 == VT_LLONG)
t |= VT_LONG; t &= t2;
/* convert to unsigned if it does not fit in a long long */ /* convert to unsigned if it does not fit in a long long */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
(t2 & (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; goto std_op;
} else { } else {
/* integer operations */ /* integer operations */
t = VT_INT; t = VT_INT | (VT_LONG & (t1 | t2));
/* convert to unsigned if it does not fit in an integer */
if ((t1 & VT_LONG) || (t2 & VT_LONG))
t |= VT_LONG;
/* convert to unsigned if it does not fit in an integer */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
t |= VT_UNSIGNED; t |= VT_UNSIGNED;
@ -2741,7 +2738,6 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
t1 &= ~VT_DEFSIGN; t1 &= ~VT_DEFSIGN;
t2 &= ~VT_DEFSIGN; t2 &= ~VT_DEFSIGN;
} }
/* XXX: bitfields ? */ /* XXX: bitfields ? */
if (t1 != t2) if (t1 != t2)
return 0; return 0;
@ -2790,14 +2786,7 @@ static void type_to_str(char *buf, int buf_size,
t = type->t; t = type->t;
bt = t & VT_BTYPE; bt = t & VT_BTYPE;
buf[0] = '\0'; 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) if (t & VT_EXTERN)
pstrcat(buf, buf_size, "extern "); pstrcat(buf, buf_size, "extern ");
if (t & VT_STATIC) if (t & VT_STATIC)
@ -2806,17 +2795,20 @@ static void type_to_str(char *buf, int buf_size,
pstrcat(buf, buf_size, "typedef "); pstrcat(buf, buf_size, "typedef ");
if (t & VT_INLINE) if (t & VT_INLINE)
pstrcat(buf, buf_size, "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_size -= strlen(buf);
buf += 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) { switch(bt) {
case VT_VOID: case VT_VOID:
@ -2833,10 +2825,16 @@ static void type_to_str(char *buf, int buf_size,
goto add_tstr; goto add_tstr;
case VT_INT: case VT_INT:
tstr = "int"; tstr = "int";
goto add_tstr; goto maybe_long;
case VT_LLONG: case VT_LLONG:
tstr = "long long"; 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: case VT_FLOAT:
tstr = "float"; tstr = "float";
goto add_tstr; goto add_tstr;
@ -2902,7 +2900,7 @@ static void type_to_str(char *buf, int buf_size,
casts if needed. */ casts if needed. */
static void gen_assign_cast(CType *dt) static void gen_assign_cast(CType *dt)
{ {
CType *st, *type1, *type2, tmp_type1, tmp_type2; CType *st, *type1, *type2;
char buf1[256], buf2[256]; char buf1[256], buf2[256];
int dbt, sbt; int dbt, sbt;
@ -2958,7 +2956,7 @@ static void gen_assign_cast(CType *dt)
in pointer target signedness. Do warn for different in pointer target signedness. Do warn for different
base types, though, in particular for unsigned enums base types, though, in particular for unsigned enums
and signed int targets. */ 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) || IS_ENUM(type1->t) || IS_ENUM(type2->t)
) )
tcc_warning("assignment from incompatible pointer type"); tcc_warning("assignment from incompatible pointer type");
@ -2982,11 +2980,7 @@ static void gen_assign_cast(CType *dt)
break; break;
case VT_STRUCT: case VT_STRUCT:
case_VT_STRUCT: case_VT_STRUCT:
tmp_type1 = *dt; if (!is_compatible_unqualified_types(dt, st)) {
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)) {
error: error:
type_to_str(buf1, sizeof(buf1), st, NULL); type_to_str(buf1, sizeof(buf1), st, NULL);
type_to_str(buf2, sizeof(buf2), dt, NULL); type_to_str(buf2, sizeof(buf2), dt, NULL);
@ -3775,10 +3769,10 @@ do_decl:
t.t = VT_INT; t.t = VT_INT;
if (nl >= 0) { if (nl >= 0) {
if (pl != (unsigned)pl) if (pl != (unsigned)pl)
t.t = VT_LLONG; t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
t.t |= VT_UNSIGNED; t.t |= VT_UNSIGNED;
} else if (pl != (int)pl || nl != (int)nl) } 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->type.t = type->t = t.t | VT_ENUM;
s->c = 0; s->c = 0;
/* set type for enum members */ /* set type for enum members */
@ -3791,7 +3785,8 @@ do_decl:
if (ll == (unsigned)ll) if (ll == (unsigned)ll)
continue; 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 { } else {
c = 0; c = 0;
@ -3964,7 +3959,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
bt = u; bt = u;
} }
if (u != VT_INT) if (u != VT_INT)
t = (t & ~VT_BTYPE) | u; t = (t & ~(VT_BTYPE|VT_LONG)) | u;
typespec_found = 1; typespec_found = 1;
break; break;
case TOK_VOID: case TOK_VOID:
@ -3978,11 +3973,9 @@ static int parse_btype(CType *type, AttributeDef *ad)
goto basic_type; goto basic_type;
case TOK_LONG: case TOK_LONG:
if ((t & VT_BTYPE) == VT_DOUBLE) { if ((t & VT_BTYPE) == VT_DOUBLE) {
#ifndef TCC_TARGET_PE t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE;
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE; } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) {
#endif t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG;
} else if (t & VT_LONG) {
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LLONG;
} else { } else {
u = VT_LONG; u = VT_LONG;
goto basic_type; goto basic_type;
@ -4003,12 +3996,8 @@ static int parse_btype(CType *type, AttributeDef *ad)
u = VT_FLOAT; u = VT_FLOAT;
goto basic_type; goto basic_type;
case TOK_DOUBLE: case TOK_DOUBLE:
if (t & VT_LONG) { if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) {
#ifdef TCC_TARGET_PE t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE;
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_DOUBLE;
#else
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE;
#endif
} else { } else {
u = VT_DOUBLE; u = VT_DOUBLE;
goto basic_type; goto basic_type;
@ -4098,7 +4087,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
parse_attribute(ad); parse_attribute(ad);
if (ad->attr_mode) { if (ad->attr_mode) {
u = ad->attr_mode -1; u = ad->attr_mode -1;
t = (t & ~VT_BTYPE) | u; t = (t & ~(VT_BTYPE|VT_LONG)) | u;
} }
break; break;
/* GNUC typeof */ /* GNUC typeof */
@ -4118,7 +4107,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
s = sym_find(tok); s = sym_find(tok);
if (!s || !(s->type.t & VT_TYPEDEF)) if (!s || !(s->type.t & VT_TYPEDEF))
goto the_end; goto the_end;
t &= ~VT_BTYPE; t &= ~(VT_BTYPE|VT_LONG);
u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u;
type->t = (s->type.t & ~VT_TYPEDEF) | u; type->t = (s->type.t & ~VT_TYPEDEF) | u;
type->ref = s->type.ref; type->ref = s->type.ref;
@ -4139,13 +4128,13 @@ the_end:
if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE)
t |= VT_UNSIGNED; t |= VT_UNSIGNED;
} }
/* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */
/* long is never used as type */ bt = t & (VT_BTYPE|VT_LONG);
if (t & VT_LONG) if (bt == VT_LONG)
#if PTR_SIZE == 8 && !defined TCC_TARGET_PE t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT;
t = (t & ~VT_BTYPE) | VT_LLONG; #ifdef TCC_TARGET_PE
#else if (bt == VT_LDOUBLE)
t = (t & ~VT_BTYPE) | VT_INT; t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE;
#endif #endif
type->t = t; type->t = t;
return type_found; return type_found;
@ -4544,9 +4533,13 @@ ST_FUNC void unary(void)
case TOK_EXTENSION: case TOK_EXTENSION:
next(); next();
goto tok_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_CINT:
case TOK_CCHAR: case TOK_CCHAR:
case TOK_LCHAR:
t = VT_INT; t = VT_INT;
push_tokc: push_tokc:
type.t = t; type.t = t;
@ -4572,14 +4565,10 @@ ST_FUNC void unary(void)
t = VT_LDOUBLE; t = VT_LDOUBLE;
goto push_tokc; goto push_tokc;
case TOK_CLONG: case TOK_CLONG:
t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG;
goto push_tokc;
case TOK_CULONG: case TOK_CULONG:
#ifdef TCC_LONG_ARE_64_BIT t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED;
t = VT_LLONG | VT_LONG;
#else
t = VT_INT | VT_LONG;
#endif
if (tok == TOK_CULONG)
t |= VT_UNSIGNED;
goto push_tokc; goto push_tokc;
case TOK___FUNCTION__: case TOK___FUNCTION__:
if (!gnu_ext) if (!gnu_ext)
@ -5491,7 +5480,11 @@ static void expr_cond(void)
} }
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
/* cast to biggest op */ /* 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 */ /* convert to unsigned if it does not fit in a long long */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
(t2 & (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; type.t = VT_VOID;
} else { } else {
/* integer operations */ /* 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 */ /* convert to unsigned if it does not fit in an integer */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
(t2 & (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; *(double *)ptr = vtop->c.d;
break; break;
case VT_LDOUBLE: 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) #if (defined __i386__ || defined __x86_64__) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
else if (sizeof (long double) >= 10) if (sizeof (long double) >= 10) /* zero pad ten-byte LD */
memcpy(memset(ptr, 0, LDOUBLE_SIZE), &vtop->c.ld, 10); memcpy(ptr, &vtop->c.ld, 10);
#ifdef __TINYC__ #ifdef __TINYC__
else if (sizeof (long double) == sizeof (double)) else if (sizeof (long double) == sizeof (double))
__asm__("fldl %1\nfstpt %0\n" : "=m" __asm__("fldl %1\nfstpt %0\n" : "=m" (ptr) : "m" (vtop->c.ld));
(memset(ptr, 0, LDOUBLE_SIZE), ptr) : "m" (vtop->c.ld));
#endif #endif
else
#endif #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"); tcc_error("can't cross compile long double constants");
break; break;
#if PTR_SIZE != 8 #if PTR_SIZE != 8

122
tccpp.c
View File

@ -89,7 +89,7 @@ static const unsigned char tok_two_chars[] =
'^','=', TOK_A_XOR, '^','=', TOK_A_XOR,
'|','=', TOK_A_OR, '|','=', TOK_A_OR,
'-','>', TOK_ARROW, '-','>', TOK_ARROW,
'.','.', 0xa8, // C++ token ? '.','.', TOK_TWODOTS,
'#','#', TOK_TWOSHARPS, '#','#', TOK_TWOSHARPS,
0 0
}; };
@ -1017,23 +1017,18 @@ static inline int tok_size(const int *p)
case TOK_LCHAR: case TOK_LCHAR:
case TOK_CFLOAT: case TOK_CFLOAT:
case TOK_LINENUM: case TOK_LINENUM:
#ifndef TCC_LONG_ARE_64_BIT
case TOK_CLONG;
case TOK_CULONG;
#endif
return 1 + 1; return 1 + 1;
case TOK_STR: case TOK_STR:
case TOK_LSTR: case TOK_LSTR:
case TOK_PPNUM: case TOK_PPNUM:
case TOK_PPSTR: case TOK_PPSTR:
return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2); 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_CDOUBLE:
case TOK_CLLONG: case TOK_CLLONG:
case TOK_CULLONG: case TOK_CULLONG:
#ifdef TCC_LONG_ARE_64_BIT
case TOK_CLONG;
case TOK_CULONG;
#endif
return 1 + 2; return 1 + 2;
case TOK_CLDOUBLE: case TOK_CLDOUBLE:
return 1 + LDOUBLE_SIZE / 4; 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_LCHAR:
case TOK_CFLOAT: case TOK_CFLOAT:
case TOK_LINENUM: case TOK_LINENUM:
#ifndef TCC_LONG_ARE_64_BIT #if LONG_SIZE == 4
case TOK_CLONG: case TOK_CLONG:
case TOK_CULONG: case TOK_CULONG:
#endif #endif
@ -1173,7 +1168,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
case TOK_CDOUBLE: case TOK_CDOUBLE:
case TOK_CLLONG: case TOK_CLLONG:
case TOK_CULLONG: case TOK_CULLONG:
#ifdef TCC_LONG_ARE_64_BIT #if LONG_SIZE == 8
case TOK_CLONG: case TOK_CLONG:
case TOK_CULONG: case TOK_CULONG:
#endif #endif
@ -1227,17 +1222,20 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
tab = cv->tab; tab = cv->tab;
switch(*t = *p++) { switch(*t = *p++) {
#if LONG_SIZE == 4
case TOK_CLONG:
#endif
case TOK_CINT: case TOK_CINT:
case TOK_CUINT:
case TOK_CCHAR: case TOK_CCHAR:
case TOK_LCHAR: case TOK_LCHAR:
case TOK_LINENUM: case TOK_LINENUM:
#ifndef TCC_LONG_ARE_64_BIT cv->i = *p++;
case TOK_CLONG: break;
#if LONG_SIZE == 4
case TOK_CULONG: case TOK_CULONG:
#endif #endif
tab[0] = *p++; case TOK_CUINT:
cv->i = (*t == TOK_CUINT) ? (unsigned)cv->i : (int)cv->i; cv->i = (unsigned)*p++;
break; break;
case TOK_CFLOAT: case TOK_CFLOAT:
tab[0] = *p++; tab[0] = *p++;
@ -1253,7 +1251,7 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
case TOK_CDOUBLE: case TOK_CDOUBLE:
case TOK_CLLONG: case TOK_CLLONG:
case TOK_CULLONG: case TOK_CULLONG:
#ifdef TCC_LONG_ARE_64_BIT #if LONG_SIZE == 8
case TOK_CLONG: case TOK_CLONG:
case TOK_CULONG: case TOK_CULONG:
#endif #endif
@ -2206,23 +2204,24 @@ static void parse_string(const char *s, int len)
tcc_free(p); tcc_free(p);
if (sep == '\'') { if (sep == '\'') {
int char_size; int char_size, i, n, c;
/* XXX: make it portable */ /* XXX: make it portable */
if (!is_long) if (!is_long)
char_size = 1; tok = TOK_CCHAR, char_size = 1;
else else
char_size = sizeof(nwchar_t); tok = TOK_LCHAR, char_size = sizeof(nwchar_t);
if (tokcstr.size <= char_size) n = tokcstr.size / char_size - 1;
if (n < 1)
tcc_error("empty character constant"); tcc_error("empty character constant");
if (tokcstr.size > 2 * char_size) if (n > 1)
tcc_warning("multi-character character constant"); tcc_warning("multi-character character constant");
if (!is_long) { for (c = i = 0; i < n; ++i) {
tokc.i = *(int8_t *)tokcstr.data; if (is_long)
tok = TOK_CCHAR; c = ((nwchar_t *)tokcstr.data)[i];
} else { else
tokc.i = *(nwchar_t *)tokcstr.data; c = (c << 8) | ((char *)tokcstr.data)[i];
tok = TOK_LCHAR;
} }
tokc.i = c;
} else { } else {
tokc.str.size = tokcstr.size; tokc.str.size = tokcstr.size;
tokc.str.data = tokcstr.data; tokc.str.data = tokcstr.data;
@ -2456,7 +2455,7 @@ static void parse_number(const char *p)
} }
} else { } else {
unsigned long long n, n1; unsigned long long n, n1;
int lcount, ucount, must_64bit; int lcount, ucount, ov = 0;
const char *p1; const char *p1;
/* integer number */ /* integer number */
@ -2483,14 +2482,13 @@ static void parse_number(const char *p)
n1 = n; n1 = n;
n = n * b + t; n = n * b + t;
/* detect overflow */ /* detect overflow */
/* XXX: this test is not reliable */ if (n1 >= 0x1000000000000000ULL && n / b != n1)
if (n < n1) ov = 1;
tcc_error("integer constant overflow");
} }
/* Determine the characteristics (unsigned and/or 64bit) the type of /* Determine the characteristics (unsigned and/or 64bit) the type of
the constant must have according to the constant suffix(es) */ the constant must have according to the constant suffix(es) */
lcount = ucount = must_64bit = 0; lcount = ucount = 0;
p1 = p; p1 = p;
for(;;) { for(;;) {
t = toup(ch); t = toup(ch);
@ -2500,8 +2498,6 @@ static void parse_number(const char *p)
if (lcount && *(p - 1) != ch) if (lcount && *(p - 1) != ch)
tcc_error("incorrect integer suffix: %s", p1); tcc_error("incorrect integer suffix: %s", p1);
lcount++; lcount++;
if (lcount == 2)
must_64bit = 1;
ch = *p++; ch = *p++;
} else if (t == 'U') { } else if (t == 'U') {
if (ucount >= 1) 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 */ /* Determine if it needs 64 bits and/or unsigned in order to fit */
if (n & 0xffffffff00000000LL || must_64bit) { if (ucount == 0 && b == 10) {
tok = TOK_CLLONG; if (lcount <= (LONG_SIZE == 4)) {
n1 = n >> 32; if (n >= 0x80000000U)
} else if (lcount) { lcount = (LONG_SIZE == 4) + 1;
#ifdef TCC_LONG_ARE_64_BIT }
n1 = n >> 32; if (n >= 0x8000000000000000ULL)
#else ov = 1, ucount = 1;
n1 = n; } else {
#endif if (lcount <= (LONG_SIZE == 4)) {
tok = TOK_CLONG; if (n >= 0x100000000ULL)
} else { lcount = (LONG_SIZE == 4) + 1;
tok = TOK_CINT; else if (n >= 0x80000000U)
n1 = n; ucount = 1;
}
if (n >= 0x8000000000000000ULL)
ucount = 1;
} }
/* Whether type must be unsigned to hold the constant's value */ if (ov)
if (ucount || ((n1 >> 31) && (b != 10))) { tcc_warning("integer constant overflow");
if (tok == TOK_CLLONG)
tok = TOK_CULLONG; tok = TOK_CINT;
else if (tok == TOK_CLONG) if (lcount) {
tok = TOK_CULONG; tok = TOK_CLONG;
else if (lcount == 2)
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; tok = TOK_CLLONG;
else }
tcc_error("integer constant overflow"); if (ucount)
} ++tok; /* TOK_CU... */
tokc.i = n; tokc.i = n;
} }
if (ch) if (ch)

View File

@ -113,7 +113,7 @@ for %%f in (*tcc.exe *tcc.dll) do @del %%f
:compiler :compiler
%CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL %CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL
@if errorlevel 1 goto :the_end @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% %CC% -o %PX%-tcc.exe ..\tcc.c %DX%
@if (%TCC_FILES%)==(no) goto :files-done @if (%TCC_FILES%)==(no) goto :files-done