From 3709f8de14187082b31647865922ee5fc6827018 Mon Sep 17 00:00:00 2001 From: Arthur Williams Date: Sun, 22 Nov 2020 00:02:09 -0600 Subject: [PATCH] Treat func pointers with different return types as not compatible Tcc considered function ptrs with different return types to be compatible which disallowed some otherwise valid operations like: `_Generic(foo, int(*)():0, void(*)(void):1)` which would fail to compile with a error message of "type match twice" This changed also required longjump's return type to be void and munmap's to be int to be compatible with standard headers. --- tccgen.c | 21 ++++++++++++--------- tccpp.c | 4 ++-- tests/tests2/94_generic.c | 6 +++++- tests/tests2/94_generic.expect | 1 + 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/tccgen.c b/tccgen.c index 26e9f53e..3b2201ca 100644 --- a/tccgen.c +++ b/tccgen.c @@ -80,7 +80,7 @@ ST_DATA int func_var; /* true if current function is variadic (used by return in ST_DATA int func_vc; static int last_line_num, new_file, func_ind; /* debug info control */ ST_DATA const char *funcname; -ST_DATA CType int_type, func_old_type, char_type, char_pointer_type; +ST_DATA CType int_type, func_old_type, char_type, char_pointer_type, func_mem_move, void_type, void_ptr_type; static CString initstr; #if PTR_SIZE == 4 @@ -800,6 +800,14 @@ ST_FUNC void tccgen_init(TCCState *s1) char_pointer_type = char_type; mk_pointer(&char_pointer_type); + void_type.t = VT_VOID; + void_ptr_type = void_type; + mk_pointer(&void_ptr_type); + func_mem_move.t = VT_FUNC; + func_mem_move.ref = sym_push(SYM_FIELD, &void_ptr_type, 0, 0); + func_mem_move.ref->f.func_call = FUNC_CDECL; + func_mem_move.ref->f.func_type = FUNC_OLD; + func_old_type.t = VT_FUNC; func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); func_old_type.ref->f.func_call = FUNC_CDECL; @@ -3029,16 +3037,11 @@ static int is_compatible_func(CType *type1, CType *type2) && s1->f.func_type != FUNC_OLD && s2->f.func_type != FUNC_OLD) return 0; - /* we should check the function return type for FUNC_OLD too - but that causes problems with the internally used support - functions such as TOK_memmove */ - if (s1->f.func_type == FUNC_OLD && !s1->next) - return 1; - if (s2->f.func_type == FUNC_OLD && !s2->next) - return 1; for (;;) { if (!is_compatible_unqualified_types(&s1->type, &s2->type)) return 0; + if (s1->f.func_type == FUNC_OLD || s2->f.func_type == FUNC_OLD ) + return 1; s1 = s1->next; s2 = s2->next; if (!s1) @@ -3907,7 +3910,7 @@ ST_FUNC void vstore(void) else #endif /* Use memmove, rather than memcpy, as dest and src may be same: */ - vpush_global_sym(&func_old_type, TOK_memmove); + vpush_global_sym(&func_mem_move, TOK_memmove); vswap(); /* source */ diff --git a/tccpp.c b/tccpp.c index 2c0dab94..992019fa 100644 --- a/tccpp.c +++ b/tccpp.c @@ -3721,10 +3721,10 @@ static void tcc_predefs(CString *cstr) "__BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__))\n" #endif "__BUILTIN(void,abort,(void))\n" - "__BOUND(int,longjmp,())\n" + "__BOUND(void,longjmp,())\n" #ifndef TCC_TARGET_PE "__BOUND(void*,mmap,())\n" - "__BOUND(void*,munmap,())\n" + "__BOUND(int,munmap,())\n" #endif "#undef __BUILTINBC\n" "#undef __BUILTIN\n" diff --git a/tests/tests2/94_generic.c b/tests/tests2/94_generic.c index 6e85c025..4a68bcdd 100644 --- a/tests/tests2/94_generic.c +++ b/tests/tests2/94_generic.c @@ -21,10 +21,12 @@ int b_f() } typedef int (*fptr)(int); +typedef void (*vfptr)(int); int foo(int i) { return i; } +void void_foo(int i) {} typedef int int_type1; @@ -66,7 +68,9 @@ int main() long long: "long long")); i = _Generic(l, long: 1, int: 2); printf("%d\n", i); - i = _Generic(foo, fptr: 3, int: 4); + i = _Generic(foo, fptr: 3, int: 4, vfptr: 5); + printf("%d\n", i); + i = _Generic(void_foo, fptr: 3, int: 4, vfptr: 5); printf("%d\n", i); (void)_Generic((int(*)[2]){0}, int(*)[2]:0, int(*)[4]:0); //shouldn't match twice diff --git a/tests/tests2/94_generic.expect b/tests/tests2/94_generic.expect index 748d78fa..80d4ed9b 100644 --- a/tests/tests2/94_generic.expect +++ b/tests/tests2/94_generic.expect @@ -12,3 +12,4 @@ long 1 3 +5