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"
master
matthias 2017-07-10 17:44:53 +02:00
parent 0cc24d0e84
commit fdc18d307a
5 changed files with 106 additions and 23 deletions

13
tcc.h
View File

@ -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 */

View File

@ -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
View File

@ -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) {

View File

@ -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;
}

View File

@ -1,9 +1,12 @@
20
10
20
123
2
0
5
1
2
3
1
4
long