diff --git a/tccabf.h b/tccabf.h new file mode 100644 index 0000000..808485c --- /dev/null +++ b/tccabf.h @@ -0,0 +1,74 @@ +/* Attributes, built-ins, and features/extensions */ +/* XXX: handle all tokens generically since speed is not critical */ + +#define DEF_ATTR0(ID) DEF(TOK_##ID, #ID) +#define DEF_ATTR2(ID) DEF(TOK_##ID##1, #ID) DEF(TOK_##ID##2, "__" #ID "__") +#define DEF_ATTR3(ID, N3) DEF_ATTR2(ID) DEF(TOK_##ID##3, N3) +#define DEF_BUILTIN(ID) DEF(TOK_builtin_##ID, "__builtin_" #ID) +#define DEF_FEATURE(ID) DEF(TOK_FEATURE_##ID, "c_" #ID) + +#ifdef DEF_SUPPORTED +static int supported_attrs[] = { +#else +#define DEF_FIRST(ID) +#endif + DEF_FIRST(TOK_section1) + DEF_ATTR2(section) + DEF_ATTR2(aligned) + DEF_ATTR2(packed) + DEF_ATTR2(weak) + DEF_ATTR2(alias) + DEF_ATTR2(unused) + DEF_ATTR3(cdecl, "__cdecl") + DEF_ATTR3(stdcall, "__stdcall") + DEF_ATTR3(fastcall, "__fastcall") + DEF_ATTR2(regparm) + DEF_ATTR2(cleanup) + DEF_ATTR2(constructor) + DEF_ATTR2(destructor) + DEF_ATTR2(always_inline) + DEF_ATTR0(dllexport) + DEF_ATTR0(dllimport) + DEF_ATTR0(nodecorate) + DEF_ATTR3(noreturn, "_Noreturn") + DEF_ATTR2(visibility) + DEF_ATTR0(__mode__) +#ifdef DEF_SUPPORTED +}; static int supported_builtins[] = { +#endif + DEF_FIRST(TOK_BUILTIN_types_compatible_p) + DEF_BUILTIN(types_compatible_p) + DEF_BUILTIN(choose_expr) + DEF_BUILTIN(constant_p) + DEF_BUILTIN(frame_address) + DEF_BUILTIN(return_address) + DEF_BUILTIN(expect) + /*DEF_BUILTIN(VA_LIST, "va_list")*/ +#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 || \ + defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 + DEF_BUILTIN(va_start) +#endif +#if defined TCC_TARGET_X86_64 + DEF_BUILTIN(va_arg_types) +#endif +#if defined TCC_TARGET_ARM64 + DEF_BUILTIN(va_arg) +#endif +#ifdef DEF_SUPPORTED +}; static int supported_features[] = { +#endif + DEF_FIRST(TOK_FEATURE_alignas) + DEF_FEATURE(alignas) + DEF_FEATURE(alignof) + DEF_FEATURE(atomic) + DEF_FEATURE(generic_selections) + DEF_FEATURE(static_assert) +#ifdef DEF_SUPPORTED +}; +#endif +#undef DEF_ATTR0 +#undef DEF_ATTR2 +#undef DEF_ATTR3 +#undef DEF_BUILTIN +#undef DEF_FEATURE +#undef DEF_FIRST diff --git a/tccgen.c b/tccgen.c index e0b5fd6..ab13d32 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4335,8 +4335,8 @@ redo: t = tok; next(); switch(t) { - case TOK_CLEANUP1: - case TOK_CLEANUP2: + case TOK_cleanup1: + case TOK_cleanup2: { Sym *s; @@ -4353,28 +4353,28 @@ redo: skip(')'); break; } - case TOK_CONSTRUCTOR1: - case TOK_CONSTRUCTOR2: + case TOK_constructor1: + case TOK_constructor2: ad->f.func_ctor = 1; break; - case TOK_DESTRUCTOR1: - case TOK_DESTRUCTOR2: + case TOK_destructor1: + case TOK_destructor2: ad->f.func_dtor = 1; break; - case TOK_ALWAYS_INLINE1: - case TOK_ALWAYS_INLINE2: + case TOK_always_inline1: + case TOK_always_inline2: ad->f.func_alwinl = 1; break; - case TOK_SECTION1: - case TOK_SECTION2: + case TOK_section1: + case TOK_section2: skip('('); parse_mult_str(&astr, "section name"); ad->section = find_section(tcc_state, (char *)astr.data); skip(')'); cstr_free(&astr); break; - case TOK_ALIAS1: - case TOK_ALIAS2: + case TOK_alias1: + case TOK_alias2: skip('('); parse_mult_str(&astr, "alias(\"target\")"); ad->alias_target = /* save string as token, for later */ @@ -4382,8 +4382,8 @@ redo: skip(')'); cstr_free(&astr); break; - case TOK_VISIBILITY1: - case TOK_VISIBILITY2: + case TOK_visibility1: + case TOK_visibility2: skip('('); parse_mult_str(&astr, "visibility(\"default|hidden|internal|protected\")"); @@ -4400,8 +4400,8 @@ redo: skip(')'); cstr_free(&astr); break; - case TOK_ALIGNED1: - case TOK_ALIGNED2: + case TOK_aligned1: + case TOK_aligned2: if (tok == '(') { next(); n = expr_const(); @@ -4415,36 +4415,36 @@ redo: if (n != 1 << (ad->a.aligned - 1)) tcc_error("alignment of %d is larger than implemented", n); break; - case TOK_PACKED1: - case TOK_PACKED2: + case TOK_packed1: + case TOK_packed2: ad->a.packed = 1; break; - case TOK_WEAK1: - case TOK_WEAK2: + case TOK_weak1: + case TOK_weak2: ad->a.weak = 1; break; - case TOK_UNUSED1: - case TOK_UNUSED2: + case TOK_unused1: + case TOK_unused2: /* currently, no need to handle it because tcc does not track unused objects */ break; - case TOK_NORETURN1: - case TOK_NORETURN2: + case TOK_noreturn1: + case TOK_noreturn2: ad->f.func_noreturn = 1; break; - case TOK_CDECL1: - case TOK_CDECL2: - case TOK_CDECL3: + case TOK_cdecl1: + case TOK_cdecl2: + case TOK_cdecl3: ad->f.func_call = FUNC_CDECL; break; - case TOK_STDCALL1: - case TOK_STDCALL2: - case TOK_STDCALL3: + case TOK_stdcall1: + case TOK_stdcall2: + case TOK_stdcall3: ad->f.func_call = FUNC_STDCALL; break; #ifdef TCC_TARGET_I386 - case TOK_REGPARM1: - case TOK_REGPARM2: + case TOK_regparm1: + case TOK_regparm2: skip('('); n = expr_const(); if (n > 3) @@ -4455,13 +4455,13 @@ redo: ad->f.func_call = FUNC_FASTCALL1 + n - 1; skip(')'); break; - case TOK_FASTCALL1: - case TOK_FASTCALL2: - case TOK_FASTCALL3: + case TOK_fastcall1: + case TOK_fastcall2: + case TOK_fastcall3: ad->f.func_call = FUNC_FASTCALLW; break; #endif - case TOK_MODE: + case TOK___mode__: skip('('); switch(tok) { case TOK_MODE_DI: @@ -4484,13 +4484,13 @@ redo: next(); skip(')'); break; - case TOK_DLLEXPORT: + case TOK_dllexport: ad->a.dllexport = 1; break; - case TOK_NODECORATE: + case TOK_nodecorate: ad->a.nodecorate = 1; break; - case TOK_DLLIMPORT: + case TOK_dllimport: ad->a.dllimport = 1; break; default: @@ -5234,7 +5234,7 @@ static int parse_btype(CType *type, AttributeDef *ad) t |= VT_INLINE; next(); break; - case TOK_NORETURN3: + case TOK_noreturn3: next(); ad->f.func_noreturn = 1; break; diff --git a/tccpp.c b/tccpp.c index 897ef15..1df257c 100644 --- a/tccpp.c +++ b/tccpp.c @@ -93,6 +93,19 @@ static const unsigned char tok_two_chars[] = 0 }; +#define DEF(id, str) + 1 +#define DEF_FIRST(ID) ID, 0 +#define DEF_SUPPORTED +#include "tccabf.h" +#undef DEF +#undef DEF_SUPPORTED + +static int *supported_arr[] = { + supported_attrs, supported_builtins, + /* We have only one profile, so __has_extension == __has_feature */ + supported_features, supported_features +}; + static void next_nomacro(void); ST_FUNC void skip(int c) @@ -1410,6 +1423,23 @@ ST_FUNC void free_defines(Sym *b) } } +ST_INLN int supported_check(int t, int type) +{ + int* arr = supported_arr[type]; + + if (t >= arr[0] && t <= arr[0] + arr[1]) + { + return 1; + } + return 0; +} + +ST_INLN int defined_check(int t) +{ + /* Ignore __has_include because it's a dummy implementation */ + return !!define_find(t) || t >= TOK___HAS_ATTRIBUTE && t <= TOK___HAS_FEATURE; +} + /* label lookup */ ST_FUNC Sym *label_find(int v) { @@ -1502,7 +1532,7 @@ static int expr_preprocess(void) expect("identifier"); if (tcc_state->run_test) maybe_run_test(tcc_state); - c = define_find(tok) != 0; + c = defined_check(tok); if (t == '(') { next_nomacro(); if (tok != ')') @@ -1510,7 +1540,7 @@ static int expr_preprocess(void) } tok = TOK_CINT; tokc.i = c; - } else if (1 && tok == TOK___HAS_INCLUDE) { + } else if (tok == TOK___HAS_INCLUDE) { next(); /* XXX check if correct to use expansion */ skip('('); while (tok != ')' && tok != TOK_EOF) @@ -1519,6 +1549,18 @@ static int expr_preprocess(void) expect("')'"); tok = TOK_CINT; tokc.i = 0; + } else if (tok >= TOK___HAS_ATTRIBUTE && tok <= TOK___HAS_FEATURE) { + t = tok; + next(); + skip('('); + if (tok < TOK_IDENT) + expect("identifier"); + c = supported_check(tok, t - TOK___HAS_ATTRIBUTE); + next(); + if (tok != ')') + expect("')'"); + tok = TOK_CINT; + tokc.i = c; } else if (tok >= TOK_IDENT) { /* if undefined macro, replace with zero, check for func-like */ t = tok; @@ -1965,7 +2007,7 @@ include_done: file->ifndef_macro = tok; } } - c = (define_find(tok) != 0) ^ c; + c = defined_check(tok) ^ c; do_if: if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) tcc_error("memory full (ifdef)"); diff --git a/tcctok.h b/tcctok.h index d4c1ef5..52fc6d5 100644 --- a/tcctok.h +++ b/tcctok.h @@ -93,6 +93,13 @@ DEF(TOK___FUNCTION__, "__FUNCTION__") DEF(TOK___VA_ARGS__, "__VA_ARGS__") DEF(TOK___COUNTER__, "__COUNTER__") + + /* The order of these matters, see tccabf.h and tccpp.c */ + DEF(TOK___HAS_ATTRIBUTE, "__has_attribute") + DEF(TOK___HAS_BUILTIN, "__has_builtin") + DEF(TOK___HAS_EXTENSION, "__has_extension") + DEF(TOK___HAS_FEATURE, "__has_feature") + /* Not implemented (dummy) */ DEF(TOK___HAS_INCLUDE, "__has_include") /* special identifiers */ @@ -107,74 +114,15 @@ DEF(TOK___mzerodf, "__mzerodf") /* -0.0 */ #endif -/* attribute identifiers */ -/* XXX: handle all tokens generically since speed is not critical */ - DEF(TOK_SECTION1, "section") - DEF(TOK_SECTION2, "__section__") - DEF(TOK_ALIGNED1, "aligned") - DEF(TOK_ALIGNED2, "__aligned__") - DEF(TOK_PACKED1, "packed") - DEF(TOK_PACKED2, "__packed__") - DEF(TOK_WEAK1, "weak") - DEF(TOK_WEAK2, "__weak__") - DEF(TOK_ALIAS1, "alias") - DEF(TOK_ALIAS2, "__alias__") - DEF(TOK_UNUSED1, "unused") - DEF(TOK_UNUSED2, "__unused__") - DEF(TOK_CDECL1, "cdecl") - DEF(TOK_CDECL2, "__cdecl") - DEF(TOK_CDECL3, "__cdecl__") - DEF(TOK_STDCALL1, "stdcall") - DEF(TOK_STDCALL2, "__stdcall") - DEF(TOK_STDCALL3, "__stdcall__") - DEF(TOK_FASTCALL1, "fastcall") - DEF(TOK_FASTCALL2, "__fastcall") - DEF(TOK_FASTCALL3, "__fastcall__") - DEF(TOK_REGPARM1, "regparm") - DEF(TOK_REGPARM2, "__regparm__") - DEF(TOK_CLEANUP1, "cleanup") - DEF(TOK_CLEANUP2, "__cleanup__") - DEF(TOK_CONSTRUCTOR1, "constructor") - DEF(TOK_CONSTRUCTOR2, "__constructor__") - DEF(TOK_DESTRUCTOR1, "destructor") - DEF(TOK_DESTRUCTOR2, "__destructor__") - DEF(TOK_ALWAYS_INLINE1, "always_inline") - DEF(TOK_ALWAYS_INLINE2, "__always_inline__") +#include "tccabf.h" - DEF(TOK_MODE, "__mode__") + /* mode attribute values */ DEF(TOK_MODE_QI, "__QI__") DEF(TOK_MODE_DI, "__DI__") DEF(TOK_MODE_HI, "__HI__") DEF(TOK_MODE_SI, "__SI__") DEF(TOK_MODE_word, "__word__") - DEF(TOK_DLLEXPORT, "dllexport") - DEF(TOK_DLLIMPORT, "dllimport") - DEF(TOK_NODECORATE, "nodecorate") - DEF(TOK_NORETURN1, "noreturn") - DEF(TOK_NORETURN2, "__noreturn__") - DEF(TOK_NORETURN3, "_Noreturn") - DEF(TOK_VISIBILITY1, "visibility") - DEF(TOK_VISIBILITY2, "__visibility__") - - DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p") - DEF(TOK_builtin_choose_expr, "__builtin_choose_expr") - DEF(TOK_builtin_constant_p, "__builtin_constant_p") - DEF(TOK_builtin_frame_address, "__builtin_frame_address") - DEF(TOK_builtin_return_address, "__builtin_return_address") - DEF(TOK_builtin_expect, "__builtin_expect") - /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/ -#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 - DEF(TOK_builtin_va_start, "__builtin_va_start") -#elif defined TCC_TARGET_X86_64 - DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types") -#elif defined TCC_TARGET_ARM64 - DEF(TOK_builtin_va_start, "__builtin_va_start") - DEF(TOK_builtin_va_arg, "__builtin_va_arg") -#elif defined TCC_TARGET_RISCV64 - DEF(TOK_builtin_va_start, "__builtin_va_start") -#endif - /* atomic operations */ #define DEF_ATOMIC(ID) DEF(TOK_##__##ID, "__"#ID) DEF_ATOMIC(atomic_store)