aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tcc.h13
-rw-r--r--tccgen.c56
-rw-r--r--tccpp.c39
-rw-r--r--tests/tests2/94_generic.c16
-rw-r--r--tests/tests2/94_generic.expect5
5 files changed, 106 insertions, 23 deletions
diff --git a/tcc.h b/tcc.h
index 4b272f5..05371bd 100644
--- a/tcc.h
+++ b/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 */
diff --git a/tccgen.c b/tccgen.c
index d53c6b7..2754192 100644
--- a/tccgen.c
+++ b/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(",");
diff --git a/tccpp.c b/tccpp.c
index 8d003d7..5209b39 100644
--- a/tccpp.c
+++ b/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) {
diff --git a/tests/tests2/94_generic.c b/tests/tests2/94_generic.c
index fad028b..4f989f0 100644
--- a/tests/tests2/94_generic.c
+++ b/tests/tests2/94_generic.c
@@ -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;
}
diff --git a/tests/tests2/94_generic.expect b/tests/tests2/94_generic.expect
index 254a84e..b75a7d1 100644
--- a/tests/tests2/94_generic.expect
+++ b/tests/tests2/94_generic.expect
@@ -1,9 +1,12 @@
20
+10
20
123
2
+0
5
1
2
3
-1
+4
+long