mirror of
https://github.com/frida/tinycc
synced 2025-01-01 17:44:26 +03:00
mutiples fix for _Generic
* check that _Generic don't match unsigned char * with char * this case is usefull as with -funsigned-char, 'char *' are unsigned * change VT_LONG so it's now a qualifier VT_LONG are never use for code generation, but only durring parsing state, in _Generic we need to be able to make diference between 'long' and 'long long' So VT_LONG is now use as a type qualifier, it's old behaviour is still here, but we can keep trace of what was a long and what wasn't * add TOK_CLONG and TOK_CULONG tcc was directly converting value like '7171L' into TOK_CLLONG or TOK_CINT depending of the machine architecture. because of that, we was unable to make diference between a long and a long long, which doesn't work with _Generic. So now 7171L is a TOK_CLONG, and we can handle _Generic properly * check that _Generic can make diference between long and long long * uncomment "type match twice" as it should now pass tests on any platforms * add inside_generic global the point of this variable is to use VT_LONG in comparaison only when we are evaluating a _Generic. problem is with my lastest patchs tcc can now make the diference between a 'long long' and a 'long', but in 64 bit stddef.h typedef uint64_t as typedef signed long long int int64_t and stdint.h as unsigned long int, so tcc break when stdint.h and stddef.h are include together. Another solution woud be to modifie include/stddef.h so it define uint64_t as unsigned long int when processor is 64 bit, but this could break some legacy code, so for now, VT_LONG are use only inside generc. * check that _Generic parse first argument correctly * check that _Generic evaluate correctly exresion like "f() / 2"
This commit is contained in:
parent
0cc24d0e84
commit
fdc18d307a
13
tcc.h
13
tcc.h
@ -849,7 +849,6 @@ struct filespec {
|
||||
#define VT_DOUBLE 9 /* IEEE double */
|
||||
#define VT_LDOUBLE 10 /* IEEE long double */
|
||||
#define VT_BOOL 11 /* ISOC99 boolean type */
|
||||
#define VT_LONG 12 /* long integer (NEVER USED as type, only during parsing) */
|
||||
#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */
|
||||
#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */
|
||||
|
||||
@ -860,6 +859,7 @@ 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
|
||||
|
||||
/* storage */
|
||||
#define VT_EXTERN 0x00001000 /* extern definition */
|
||||
@ -939,7 +939,16 @@ struct filespec {
|
||||
#define TOK_TWOSHARPS 0xca /* ## preprocessing token */
|
||||
#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 0xce /* 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_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_SAR 0x02 /* signed shift right */
|
||||
|
56
tccgen.c
56
tccgen.c
@ -42,6 +42,7 @@ ST_DATA Sym *local_label_stack;
|
||||
static int local_scope;
|
||||
static int in_sizeof;
|
||||
static int section_sym;
|
||||
static int inside_generic;
|
||||
|
||||
ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */
|
||||
ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */
|
||||
@ -2218,6 +2219,10 @@ redo:
|
||||
} 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;
|
||||
/* 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))
|
||||
@ -2226,7 +2231,11 @@ redo:
|
||||
} else {
|
||||
/* integer operations */
|
||||
t = VT_INT;
|
||||
/* 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) ||
|
||||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
|
||||
t |= VT_UNSIGNED;
|
||||
@ -2723,6 +2732,11 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
|
||||
t1 &= ~(VT_CONSTANT | VT_VOLATILE);
|
||||
t2 &= ~(VT_CONSTANT | VT_VOLATILE);
|
||||
}
|
||||
|
||||
if (!inside_generic) {
|
||||
t1 &= ~VT_LONG;
|
||||
t2 &= ~VT_LONG;
|
||||
}
|
||||
/* Default Vs explicit signedness only matters for char */
|
||||
if ((t1 & VT_BTYPE) != VT_BYTE) {
|
||||
t1 &= ~VT_DEFSIGN;
|
||||
@ -2799,6 +2813,12 @@ static void type_to_str(char *buf, int buf_size,
|
||||
tstr = "enum ";
|
||||
goto tstruct;
|
||||
}
|
||||
|
||||
if (!bt && VT_LONG & t) {
|
||||
tstr = "long";
|
||||
goto add_tstr;
|
||||
}
|
||||
|
||||
switch(bt) {
|
||||
case VT_VOID:
|
||||
tstr = "void";
|
||||
@ -2815,9 +2835,6 @@ static void type_to_str(char *buf, int buf_size,
|
||||
case VT_INT:
|
||||
tstr = "int";
|
||||
goto add_tstr;
|
||||
case VT_LONG:
|
||||
tstr = "long";
|
||||
goto add_tstr;
|
||||
case VT_LLONG:
|
||||
tstr = "long long";
|
||||
goto add_tstr;
|
||||
@ -3960,10 +3977,10 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||
case TOK_LONG:
|
||||
if ((t & VT_BTYPE) == VT_DOUBLE) {
|
||||
#ifndef TCC_TARGET_PE
|
||||
t = (t & ~VT_BTYPE) | VT_LDOUBLE;
|
||||
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE;
|
||||
#endif
|
||||
} else if ((t & VT_BTYPE) == VT_LONG) {
|
||||
t = (t & ~VT_BTYPE) | VT_LLONG;
|
||||
} else if (t & VT_LONG) {
|
||||
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LLONG;
|
||||
} else {
|
||||
u = VT_LONG;
|
||||
goto basic_type;
|
||||
@ -3984,11 +4001,11 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||
u = VT_FLOAT;
|
||||
goto basic_type;
|
||||
case TOK_DOUBLE:
|
||||
if ((t & VT_BTYPE) == VT_LONG) {
|
||||
if (t & VT_LONG) {
|
||||
#ifdef TCC_TARGET_PE
|
||||
t = (t & ~VT_BTYPE) | VT_DOUBLE;
|
||||
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_DOUBLE;
|
||||
#else
|
||||
t = (t & ~VT_BTYPE) | VT_LDOUBLE;
|
||||
t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE;
|
||||
#endif
|
||||
} else {
|
||||
u = VT_DOUBLE;
|
||||
@ -4122,7 +4139,7 @@ the_end:
|
||||
}
|
||||
|
||||
/* long is never used as type */
|
||||
if ((t & VT_BTYPE) == VT_LONG)
|
||||
if (t & VT_LONG)
|
||||
#if PTR_SIZE == 8 && !defined TCC_TARGET_PE
|
||||
t = (t & ~VT_BTYPE) | VT_LLONG;
|
||||
#else
|
||||
@ -4552,7 +4569,16 @@ ST_FUNC void unary(void)
|
||||
case TOK_CLDOUBLE:
|
||||
t = VT_LDOUBLE;
|
||||
goto push_tokc;
|
||||
|
||||
case TOK_CLONG:
|
||||
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;
|
||||
goto push_tokc;
|
||||
case TOK___FUNCTION__:
|
||||
if (!gnu_ext)
|
||||
goto tok_identifier;
|
||||
@ -4906,8 +4932,9 @@ ST_FUNC void unary(void)
|
||||
|
||||
next();
|
||||
skip('(');
|
||||
inside_generic = 1;
|
||||
expr_type(&controlling_type, expr_eq);
|
||||
controlling_type.t &= ~(VT_CONSTANT|VT_VOLATILE|VT_ARRAY);
|
||||
controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY);
|
||||
for (;;) {
|
||||
learn = 0;
|
||||
skip(',');
|
||||
@ -4926,7 +4953,7 @@ ST_FUNC void unary(void)
|
||||
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
|
||||
if (compare_types(&controlling_type, &cur_type, 0)) {
|
||||
if (has_match) {
|
||||
// tcc_error("type match twice");
|
||||
tcc_error("type match twice");
|
||||
}
|
||||
has_match = 1;
|
||||
learn = 1;
|
||||
@ -4950,6 +4977,7 @@ ST_FUNC void unary(void)
|
||||
}
|
||||
begin_macro(str, 1);
|
||||
next();
|
||||
inside_generic = 0;
|
||||
expr_eq();
|
||||
if (tok != TOK_EOF)
|
||||
expect(",");
|
||||
|
39
tccpp.c
39
tccpp.c
@ -480,6 +480,8 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv)
|
||||
switch(v) {
|
||||
case TOK_CINT:
|
||||
case TOK_CUINT:
|
||||
case TOK_CLONG:
|
||||
case TOK_CULONG:
|
||||
case TOK_CLLONG:
|
||||
case TOK_CULLONG:
|
||||
/* XXX: not quite exact, but only useful for testing */
|
||||
@ -1014,6 +1016,10 @@ 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:
|
||||
@ -1023,6 +1029,10 @@ static inline int tok_size(const int *p)
|
||||
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;
|
||||
@ -1138,6 +1148,10 @@ 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
|
||||
case TOK_CLONG:
|
||||
case TOK_CULONG:
|
||||
#endif
|
||||
str[len++] = cv->tab[0];
|
||||
break;
|
||||
case TOK_PPNUM:
|
||||
@ -1158,6 +1172,10 @@ 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
|
||||
case TOK_CLONG:
|
||||
case TOK_CULONG:
|
||||
#endif
|
||||
#if LDOUBLE_SIZE == 8
|
||||
case TOK_CLDOUBLE:
|
||||
#endif
|
||||
@ -1213,6 +1231,10 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
|
||||
case TOK_CCHAR:
|
||||
case TOK_LCHAR:
|
||||
case TOK_LINENUM:
|
||||
#ifndef TCC_LONG_ARE_64_BIT
|
||||
case TOK_CLONG:
|
||||
case TOK_CULONG:
|
||||
#endif
|
||||
tab[0] = *p++;
|
||||
cv->i = (*t == TOK_CUINT) ? (unsigned)cv->i : (int)cv->i;
|
||||
break;
|
||||
@ -1230,6 +1252,10 @@ 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
|
||||
case TOK_CLONG:
|
||||
case TOK_CULONG:
|
||||
#endif
|
||||
n = 2;
|
||||
goto copy;
|
||||
case TOK_CLDOUBLE:
|
||||
@ -2407,9 +2433,7 @@ static void parse_number(const char *p)
|
||||
if (lcount && *(p - 1) != ch)
|
||||
tcc_error("incorrect integer suffix: %s", p1);
|
||||
lcount++;
|
||||
#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
|
||||
if (lcount == 2)
|
||||
#endif
|
||||
must_64bit = 1;
|
||||
ch = *p++;
|
||||
} else if (t == 'U') {
|
||||
@ -2426,6 +2450,13 @@ static void parse_number(const char *p)
|
||||
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;
|
||||
@ -2435,7 +2466,9 @@ static void parse_number(const char *p)
|
||||
if (ucount || ((n1 >> 31) && (b != 10))) {
|
||||
if (tok == TOK_CLLONG)
|
||||
tok = TOK_CULLONG;
|
||||
else
|
||||
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) {
|
||||
|
@ -20,6 +20,8 @@ int b_f()
|
||||
return 10;
|
||||
}
|
||||
|
||||
typedef int int_type1;
|
||||
|
||||
#define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123);
|
||||
|
||||
int main()
|
||||
@ -28,24 +30,32 @@ int main()
|
||||
struct b titi;
|
||||
const int * const ptr;
|
||||
const char *ti;
|
||||
int_type1 i2;
|
||||
|
||||
i = _Generic(a, int: a_f, const int: b_f)();
|
||||
printf("%d\n", i);
|
||||
i = _Generic(a, int: a_f() / 2, const int: b_f() / 2);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(ptr, int *:1, int * const:2, default:20);
|
||||
printf("%d\n", i);
|
||||
i = gen_sw(a);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(titi, struct a:1, struct b:2, default:20);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(i2, char: 1, int : 0);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(a, char:1, int[4]:2, default:5);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(17, int :1, int **:2);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(17L, int :1, long :2);
|
||||
i = _Generic(17L, int :1, long :2, long long : 3);
|
||||
printf("%d\n", i);
|
||||
i = _Generic("17, io", const char *:1, char *:3, const int :2);
|
||||
i = _Generic("17, io", char *: 3, const char *: 1);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(ti, const char *:1, char *:3, const int :2);
|
||||
i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3,
|
||||
const signed char *:2);
|
||||
printf("%d\n", i);
|
||||
printf("%s\n", _Generic(i + 2L, long: "long", int: "int",
|
||||
long long: "long long"));
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
20
|
||||
10
|
||||
20
|
||||
123
|
||||
2
|
||||
0
|
||||
5
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
4
|
||||
long
|
||||
|
Loading…
Reference in New Issue
Block a user