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.
This commit is contained in:
Arthur Williams 2020-11-22 00:02:09 -06:00
parent 3b1a42e734
commit 3709f8de14
4 changed files with 20 additions and 12 deletions

View File

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

View File

@ -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"

View File

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

View File

@ -12,3 +12,4 @@
long
1
3
5