* 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"
Unified · Split
| @@ -849,7 +849,6 @@ struct filespec { · 848 unmodified lines | ||
| 849 | 849 | #define VT_DOUBLE 9 /* IEEE double */ |
| 850 | 850 | #define VT_LDOUBLE 10 /* IEEE long double */ |
| 851 | 851 | #define VT_BOOL 11 /* ISOC99 boolean type */ |
| 852 | −#define VT_LONG 12 /* long integer (NEVER USED as type, only during parsing) */ | |
| 853 | 852 | #define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */ |
| 854 | 853 | #define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */ |
| 855 | 854 | |
| @@ -860,6 +859,7 @@ struct filespec { · 4 unmodified lines | ||
| 860 | 859 | #define VT_CONSTANT 0x0100 /* const modifier */ |
| 861 | 860 | #define VT_VOLATILE 0x0200 /* volatile modifier */ |
| 862 | 861 | #define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */ |
| 862 | +#define VT_LONG 0x0800 | |
| 863 | 863 | |
| 864 | 864 | /* storage */ |
| 865 | 865 | #define VT_EXTERN 0x00001000 /* extern definition */ |
| @@ -939,7 +939,16 @@ struct filespec { · 73 unmodified lines | ||
| 939 | 939 | #define TOK_TWOSHARPS 0xca /* ## preprocessing token */ |
| 940 | 940 | #define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */ |
| 941 | 941 | #define TOK_NOSUBST 0xcc /* means following token has already been pp'd */ |
| 942 | −#define TOK_PPJOIN 0xce /* A '##' in the right position to mean pasting */ | |
| 942 | +#define TOK_PPJOIN 0xcd /* A '##' in the right position to mean pasting */ | |
| 943 | + | |
| 944 | +#define TOK_CLONG 0xce /* long constant */ | |
| 945 | +#define TOK_CULONG 0xcf /* unsigned long constant */ | |
| 946 | + | |
| 947 | + | |
| 948 | +#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE | |
| 949 | + #define TCC_LONG_ARE_64_BIT | |
| 950 | +#endif | |
| 951 | + | |
| 943 | 952 | |
| 944 | 953 | #define TOK_SHL 0x01 /* shift left */ |
| 945 | 954 | #define TOK_SAR 0x02 /* signed shift right */ |
| @@ -42,6 +42,7 @@ ST_DATA Sym *local_label_stack; · 41 unmodified lines | ||
| 42 | 42 | static int local_scope; |
| 43 | 43 | static int in_sizeof; |
| 44 | 44 | static int section_sym; |
| 45 | +static int inside_generic; | |
| 45 | 46 | |
| 46 | 47 | ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */ |
| 47 | 48 | ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */ |
| @@ -2218,6 +2219,10 @@ redo: · 2170 unmodified lines | ||
| 2218 | 2219 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
| 2219 | 2220 | /* cast to biggest op */ |
| 2220 | 2221 | t = VT_LLONG; |
| 2222 | + /* check if we need to keep type as long or as long long */ | |
| 2223 | + if ((t1 & VT_LONG && (t2 & (VT_BTYPE | VT_LONG)) != VT_LLONG) || | |
| 2224 | + (t2 & VT_LONG && (t1 & (VT_BTYPE | VT_LONG)) != VT_LLONG)) | |
| 2225 | + t |= VT_LONG; | |
| 2221 | 2226 | /* convert to unsigned if it does not fit in a long long */ |
| 2222 | 2227 | if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || |
| 2223 | 2228 | (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) |
| @@ -2226,7 +2231,11 @@ redo: · 2 unmodified lines | ||
| 2226 | 2231 | } else { |
| 2227 | 2232 | /* integer operations */ |
| 2228 | 2233 | t = VT_INT; |
| 2229 | − /* convert to unsigned if it does not fit in an integer */ | |
| 2234 | + | |
| 2235 | + if ((t1 & VT_LONG) || (t2 & VT_LONG)) | |
| 2236 | + t |= VT_LONG; | |
| 2237 | + | |
| 2238 | + /* convert to unsigned if it does not fit in an integer */ | |
| 2230 | 2239 | if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || |
| 2231 | 2240 | (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) |
| 2232 | 2241 | t |= VT_UNSIGNED; |
| @@ -2723,6 +2732,11 @@ static int compare_types(CType *type1, CType *type2, int unqualified) · 490 unmodified lines | ||
| 2723 | 2732 | t1 &= ~(VT_CONSTANT | VT_VOLATILE); |
| 2724 | 2733 | t2 &= ~(VT_CONSTANT | VT_VOLATILE); |
| 2725 | 2734 | } |
| 2735 | + | |
| 2736 | + if (!inside_generic) { | |
| 2737 | + t1 &= ~VT_LONG; | |
| 2738 | + t2 &= ~VT_LONG; | |
| 2739 | + } | |
| 2726 | 2740 | /* Default Vs explicit signedness only matters for char */ |
| 2727 | 2741 | if ((t1 & VT_BTYPE) != VT_BYTE) { |
| 2728 | 2742 | t1 &= ~VT_DEFSIGN; |
| @@ -2799,6 +2813,12 @@ static void type_to_str(char *buf, int buf_size, · 70 unmodified lines | ||
| 2799 | 2813 | tstr = "enum "; |
| 2800 | 2814 | goto tstruct; |
| 2801 | 2815 | } |
| 2816 | + | |
| 2817 | + if (!bt && VT_LONG & t) { | |
| 2818 | + tstr = "long"; | |
| 2819 | + goto add_tstr; | |
| 2820 | + } | |
| 2821 | + | |
| 2802 | 2822 | switch(bt) { |
| 2803 | 2823 | case VT_VOID: |
| 2804 | 2824 | tstr = "void"; |
| @@ -2815,9 +2835,6 @@ static void type_to_str(char *buf, int buf_size, · 10 unmodified lines | ||
| 2815 | 2835 | case VT_INT: |
| 2816 | 2836 | tstr = "int"; |
| 2817 | 2837 | goto add_tstr; |
| 2818 | − case VT_LONG: | |
| 2819 | − tstr = "long"; | |
| 2820 | − goto add_tstr; | |
| 2821 | 2838 | case VT_LLONG: |
| 2822 | 2839 | tstr = "long long"; |
| 2823 | 2840 | goto add_tstr; |
| @@ -3960,10 +3977,10 @@ static int parse_btype(CType *type, AttributeDef *ad) · 1136 unmodified lines | ||
| 3960 | 3977 | case TOK_LONG: |
| 3961 | 3978 | if ((t & VT_BTYPE) == VT_DOUBLE) { |
| 3962 | 3979 | #ifndef TCC_TARGET_PE |
| 3963 | − t = (t & ~VT_BTYPE) | VT_LDOUBLE; | |
| 3980 | + t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE; | |
| 3964 | 3981 | #endif |
| 3965 | − } else if ((t & VT_BTYPE) == VT_LONG) { | |
| 3966 | − t = (t & ~VT_BTYPE) | VT_LLONG; | |
| 3982 | + } else if (t & VT_LONG) { | |
| 3983 | + t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LLONG; | |
| 3967 | 3984 | } else { |
| 3968 | 3985 | u = VT_LONG; |
| 3969 | 3986 | goto basic_type; |
| @@ -3984,11 +4001,11 @@ static int parse_btype(CType *type, AttributeDef *ad) · 14 unmodified lines | ||
| 3984 | 4001 | u = VT_FLOAT; |
| 3985 | 4002 | goto basic_type; |
| 3986 | 4003 | case TOK_DOUBLE: |
| 3987 | − if ((t & VT_BTYPE) == VT_LONG) { | |
| 4004 | + if (t & VT_LONG) { | |
| 3988 | 4005 | #ifdef TCC_TARGET_PE |
| 3989 | − t = (t & ~VT_BTYPE) | VT_DOUBLE; | |
| 4006 | + t = (t & ~(VT_LONG | VT_BTYPE)) | VT_DOUBLE; | |
| 3990 | 4007 | #else |
| 3991 | − t = (t & ~VT_BTYPE) | VT_LDOUBLE; | |
| 4008 | + t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE; | |
| 3992 | 4009 | #endif |
| 3993 | 4010 | } else { |
| 3994 | 4011 | u = VT_DOUBLE; |
| @@ -4122,7 +4139,7 @@ the_end: · 127 unmodified lines | ||
| 4122 | 4139 | } |
| 4123 | 4140 | |
| 4124 | 4141 | /* long is never used as type */ |
| 4125 | − if ((t & VT_BTYPE) == VT_LONG) | |
| 4142 | + if (t & VT_LONG) | |
| 4126 | 4143 | #if PTR_SIZE == 8 && !defined TCC_TARGET_PE |
| 4127 | 4144 | t = (t & ~VT_BTYPE) | VT_LLONG; |
| 4128 | 4145 | #else |
| @@ -4552,7 +4569,16 @@ ST_FUNC void unary(void) · 423 unmodified lines | ||
| 4552 | 4569 | case TOK_CLDOUBLE: |
| 4553 | 4570 | t = VT_LDOUBLE; |
| 4554 | 4571 | goto push_tokc; |
| 4555 | − | |
| 4572 | + case TOK_CLONG: | |
| 4573 | + case TOK_CULONG: | |
| 4574 | + #ifdef TCC_LONG_ARE_64_BIT | |
| 4575 | + t = VT_LLONG | VT_LONG; | |
| 4576 | + #else | |
| 4577 | + t = VT_INT | VT_LONG; | |
| 4578 | + #endif | |
| 4579 | + if (tok == TOK_CULONG) | |
| 4580 | + t |= VT_UNSIGNED; | |
| 4581 | + goto push_tokc; | |
| 4556 | 4582 | case TOK___FUNCTION__: |
| 4557 | 4583 | if (!gnu_ext) |
| 4558 | 4584 | goto tok_identifier; |
| @@ -4906,8 +4932,9 @@ ST_FUNC void unary(void) · 347 unmodified lines | ||
| 4906 | 4932 | |
| 4907 | 4933 | next(); |
| 4908 | 4934 | skip('('); |
| 4935 | + inside_generic = 1; | |
| 4909 | 4936 | expr_type(&controlling_type, expr_eq); |
| 4910 | − controlling_type.t &= ~(VT_CONSTANT|VT_VOLATILE|VT_ARRAY); | |
| 4937 | + controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY); | |
| 4911 | 4938 | for (;;) { |
| 4912 | 4939 | learn = 0; |
| 4913 | 4940 | skip(','); |
| @@ -4926,7 +4953,7 @@ ST_FUNC void unary(void) · 12 unmodified lines | ||
| 4926 | 4953 | type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT); |
| 4927 | 4954 | if (compare_types(&controlling_type, &cur_type, 0)) { |
| 4928 | 4955 | if (has_match) { |
| 4929 | − // tcc_error("type match twice"); | |
| 4956 | + tcc_error("type match twice"); | |
| 4930 | 4957 | } |
| 4931 | 4958 | has_match = 1; |
| 4932 | 4959 | learn = 1; |
| @@ -4950,6 +4977,7 @@ ST_FUNC void unary(void) · 17 unmodified lines | ||
| 4950 | 4977 | } |
| 4951 | 4978 | begin_macro(str, 1); |
| 4952 | 4979 | next(); |
| 4980 | + inside_generic = 0; | |
| 4953 | 4981 | expr_eq(); |
| 4954 | 4982 | if (tok != TOK_EOF) |
| 4955 | 4983 | expect(","); |
| @@ -480,6 +480,8 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv) · 479 unmodified lines | ||
| 480 | 480 | switch(v) { |
| 481 | 481 | case TOK_CINT: |
| 482 | 482 | case TOK_CUINT: |
| 483 | + case TOK_CLONG: | |
| 484 | + case TOK_CULONG: | |
| 483 | 485 | case TOK_CLLONG: |
| 484 | 486 | case TOK_CULLONG: |
| 485 | 487 | /* XXX: not quite exact, but only useful for testing */ |
| @@ -1014,6 +1016,10 @@ static inline int tok_size(const int *p) · 528 unmodified lines | ||
| 1014 | 1016 | case TOK_LCHAR: |
| 1015 | 1017 | case TOK_CFLOAT: |
| 1016 | 1018 | case TOK_LINENUM: |
| 1019 | +#ifndef TCC_LONG_ARE_64_BIT | |
| 1020 | + case TOK_CLONG; | |
| 1021 | + case TOK_CULONG; | |
| 1022 | +#endif | |
| 1017 | 1023 | return 1 + 1; |
| 1018 | 1024 | case TOK_STR: |
| 1019 | 1025 | case TOK_LSTR: |
| @@ -1023,6 +1029,10 @@ static inline int tok_size(const int *p) · 3 unmodified lines | ||
| 1023 | 1029 | case TOK_CDOUBLE: |
| 1024 | 1030 | case TOK_CLLONG: |
| 1025 | 1031 | case TOK_CULLONG: |
| 1032 | +#ifdef TCC_LONG_ARE_64_BIT | |
| 1033 | + case TOK_CLONG; | |
| 1034 | + case TOK_CULONG; | |
| 1035 | +#endif | |
| 1026 | 1036 | return 1 + 2; |
| 1027 | 1037 | case TOK_CLDOUBLE: |
| 1028 | 1038 | return 1 + LDOUBLE_SIZE / 4; |
| @@ -1138,6 +1148,10 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv) · 109 unmodified lines | ||
| 1138 | 1148 | case TOK_LCHAR: |
| 1139 | 1149 | case TOK_CFLOAT: |
| 1140 | 1150 | case TOK_LINENUM: |
| 1151 | +#ifndef TCC_LONG_ARE_64_BIT | |
| 1152 | + case TOK_CLONG: | |
| 1153 | + case TOK_CULONG: | |
| 1154 | +#endif | |
| 1141 | 1155 | str[len++] = cv->tab[0]; |
| 1142 | 1156 | break; |
| 1143 | 1157 | case TOK_PPNUM: |
| @@ -1158,6 +1172,10 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv) · 14 unmodified lines | ||
| 1158 | 1172 | case TOK_CDOUBLE: |
| 1159 | 1173 | case TOK_CLLONG: |
| 1160 | 1174 | case TOK_CULLONG: |
| 1175 | +#ifdef TCC_LONG_ARE_64_BIT | |
| 1176 | + case TOK_CLONG: | |
| 1177 | + case TOK_CULONG: | |
| 1178 | +#endif | |
| 1161 | 1179 | #if LDOUBLE_SIZE == 8 |
| 1162 | 1180 | case TOK_CLDOUBLE: |
| 1163 | 1181 | #endif |
| @@ -1213,6 +1231,10 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv) · 49 unmodified lines | ||
| 1213 | 1231 | case TOK_CCHAR: |
| 1214 | 1232 | case TOK_LCHAR: |
| 1215 | 1233 | case TOK_LINENUM: |
| 1234 | +#ifndef TCC_LONG_ARE_64_BIT | |
| 1235 | + case TOK_CLONG: | |
| 1236 | + case TOK_CULONG: | |
| 1237 | +#endif | |
| 1216 | 1238 | tab[0] = *p++; |
| 1217 | 1239 | cv->i = (*t == TOK_CUINT) ? (unsigned)cv->i : (int)cv->i; |
| 1218 | 1240 | break; |
| @@ -1230,6 +1252,10 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv) · 11 unmodified lines | ||
| 1230 | 1252 | case TOK_CDOUBLE: |
| 1231 | 1253 | case TOK_CLLONG: |
| 1232 | 1254 | case TOK_CULLONG: |
| 1255 | +#ifdef TCC_LONG_ARE_64_BIT | |
| 1256 | + case TOK_CLONG: | |
| 1257 | + case TOK_CULONG: | |
| 1258 | +#endif | |
| 1233 | 1259 | n = 2; |
| 1234 | 1260 | goto copy; |
| 1235 | 1261 | case TOK_CLDOUBLE: |
| @@ -2407,9 +2433,7 @@ static void parse_number(const char *p) · 1171 unmodified lines | ||
| 2407 | 2433 | if (lcount && *(p - 1) != ch) |
| 2408 | 2434 | tcc_error("incorrect integer suffix: %s", p1); |
| 2409 | 2435 | lcount++; |
| 2410 | −#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE | |
| 2411 | 2436 | if (lcount == 2) |
| 2412 | −#endif | |
| 2413 | 2437 | must_64bit = 1; |
| 2414 | 2438 | ch = *p++; |
| 2415 | 2439 | } else if (t == 'U') { |
| @@ -2426,6 +2450,13 @@ static void parse_number(const char *p) · 10 unmodified lines | ||
| 2426 | 2450 | if (n & 0xffffffff00000000LL || must_64bit) { |
| 2427 | 2451 | tok = TOK_CLLONG; |
| 2428 | 2452 | n1 = n >> 32; |
| 2453 | + } else if (lcount) { | |
| 2454 | +#ifdef TCC_LONG_ARE_64_BIT | |
| 2455 | + n1 = n >> 32; | |
| 2456 | +#else | |
| 2457 | + n1 = n; | |
| 2458 | +#endif | |
| 2459 | + tok = TOK_CLONG; | |
| 2429 | 2460 | } else { |
| 2430 | 2461 | tok = TOK_CINT; |
| 2431 | 2462 | n1 = n; |
| @@ -2435,7 +2466,9 @@ static void parse_number(const char *p) · 3 unmodified lines | ||
| 2435 | 2466 | if (ucount || ((n1 >> 31) && (b != 10))) { |
| 2436 | 2467 | if (tok == TOK_CLLONG) |
| 2437 | 2468 | tok = TOK_CULLONG; |
| 2438 | − else | |
| 2469 | + else if (tok == TOK_CLONG) | |
| 2470 | + tok = TOK_CULONG; | |
| 2471 | + else | |
| 2439 | 2472 | tok = TOK_CUINT; |
| 2440 | 2473 | /* If decimal and no unsigned suffix, bump to 64 bits or throw error */ |
| 2441 | 2474 | } else if (n1 >> 31) { |
| @@ -20,6 +20,8 @@ int b_f() · 19 unmodified lines | ||
| 20 | 20 | return 10; |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | +typedef int int_type1; | |
| 24 | + | |
| 23 | 25 | #define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123); |
| 24 | 26 | |
| 25 | 27 | int main() |
| @@ -28,24 +30,32 @@ int main() · 2 unmodified lines | ||
| 28 | 30 | struct b titi; |
| 29 | 31 | const int * const ptr; |
| 30 | 32 | const char *ti; |
| 33 | + int_type1 i2; | |
| 31 | 34 | |
| 32 | 35 | i = _Generic(a, int: a_f, const int: b_f)(); |
| 33 | 36 | printf("%d\n", i); |
| 37 | + i = _Generic(a, int: a_f() / 2, const int: b_f() / 2); | |
| 38 | + printf("%d\n", i); | |
| 34 | 39 | i = _Generic(ptr, int *:1, int * const:2, default:20); |
| 35 | 40 | printf("%d\n", i); |
| 36 | 41 | i = gen_sw(a); |
| 37 | 42 | printf("%d\n", i); |
| 38 | 43 | i = _Generic(titi, struct a:1, struct b:2, default:20); |
| 39 | 44 | printf("%d\n", i); |
| 45 | + i = _Generic(i2, char: 1, int : 0); | |
| 46 | + printf("%d\n", i); | |
| 40 | 47 | i = _Generic(a, char:1, int[4]:2, default:5); |
| 41 | 48 | printf("%d\n", i); |
| 42 | 49 | i = _Generic(17, int :1, int **:2); |
| 43 | 50 | printf("%d\n", i); |
| 44 | − i = _Generic(17L, int :1, long :2); | |
| 51 | + i = _Generic(17L, int :1, long :2, long long : 3); | |
| 45 | 52 | printf("%d\n", i); |
| 46 | − i = _Generic("17, io", const char *:1, char *:3, const int :2); | |
| 53 | + i = _Generic("17, io", char *: 3, const char *: 1); | |
| 47 | 54 | printf("%d\n", i); |
| 48 | − i = _Generic(ti, const char *:1, char *:3, const int :2); | |
| 55 | + i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3, | |
| 56 | + const signed char *:2); | |
| 49 | 57 | printf("%d\n", i); |
| 58 | + printf("%s\n", _Generic(i + 2L, long: "long", int: "int", | |
| 59 | + long long: "long long")); | |
| 50 | 60 | return 0; |
| 51 | 61 | } |
| @@ -1,9 +1,12 @@ | ||
| 1 | 1 | 20 |
| 2 | +10 | |
| 2 | 3 | 20 |
| 3 | 4 | 123 |
| 4 | 5 | 2 |
| 6 | +0 | |
| 5 | 7 | 5 |
| 6 | 8 | 1 |
| 7 | 9 | 2 |
| 8 | 10 | 3 |
| 9 | −1 | |
| 11 | +4 | |
| 12 | +long | |