c: C2x changes to function type compatibility
WG14 N2432, the C2x removal of old-style function definitions, also changed the function type compatibility rules so that an unprototyped declaration can be compatible with a non-variadic prototyped declaration even if some function arguments are changed by the default argument promotions. I missed that change in the initial implementation for GCC of the rest of the N2432 changes, but discussion on the WG14 reflector in February suggests that this is indeed an intended change. Implement this in the C front end. Note that while this may be of use in some cases for use of pointers to unprototyped function types as a kind of generic function pointer, it's *not* possible to call such a function without a prototype visible, without getting runtime undefined behavior from the (promoted) type used in the call being incompatible with the (unpromoted) type in the prototype. Note also that GCC has a longstanding extension to allow compatibility of such a prototype with an old-style definition specifying the same type as in the prototype (which is not valid in ISO C, before old-style definitions were removed in C2x). Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/c/ * c-typeck.c (function_types_compatible_p): For C2X, treat unprototyped function as compatible with non-variadic prototyped function even if some argument types are changed by the default argument promotions. gcc/testsuite/ * gcc.dg/c11-unproto-1.c, gcc.dg/c11-unproto-2.c, gcc.dg/c2x-unproto-1.c, gcc.dg/c2x-unproto-2.c: New tests.
This commit is contained in:
parent
e4ff4ffb43
commit
cc80612621
@ -1692,7 +1692,7 @@ function_types_compatible_p (const_tree f1, const_tree f2,
|
||||
|
||||
if (args1 == NULL_TREE)
|
||||
{
|
||||
if (!self_promoting_args_p (args2))
|
||||
if (flag_isoc2x ? stdarg_p (f2) : !self_promoting_args_p (args2))
|
||||
return 0;
|
||||
/* If one of these types comes from a non-prototype fn definition,
|
||||
compare that with the other type's arglist.
|
||||
@ -1705,7 +1705,7 @@ function_types_compatible_p (const_tree f1, const_tree f2,
|
||||
}
|
||||
if (args2 == NULL_TREE)
|
||||
{
|
||||
if (!self_promoting_args_p (args1))
|
||||
if (flag_isoc2x ? stdarg_p (f1) : !self_promoting_args_p (args1))
|
||||
return 0;
|
||||
if (TYPE_ACTUAL_ARG_TYPES (f2)
|
||||
&& type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
|
||||
|
24
gcc/testsuite/gcc.dg/c11-unproto-1.c
Normal file
24
gcc/testsuite/gcc.dg/c11-unproto-1.c
Normal file
@ -0,0 +1,24 @@
|
||||
/* Test compatibility of unprototyped and prototyped function types (C2x makes
|
||||
the case of types affected by default argument promotions compatible). Test
|
||||
valid-in-C2x usages are not accepted for C11. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c11 -pedantic-errors" } */
|
||||
|
||||
void f1 (); /* { dg-message "previous declaration" } */
|
||||
void f1 (float); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "default promotion" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f2 (float); /* { dg-message "previous declaration" } */
|
||||
void f2 (); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "default promotion" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f3 (); /* { dg-message "previous declaration" } */
|
||||
void f3 (char); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "default promotion" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f4 (char); /* { dg-message "previous declaration" } */
|
||||
void f4 (); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "default promotion" "" { target *-*-* } .-1 } */
|
||||
|
||||
/* Built-in function case. */
|
||||
float sqrtf (); /* { dg-warning "conflicting types for built-in function" } */
|
21
gcc/testsuite/gcc.dg/c11-unproto-2.c
Normal file
21
gcc/testsuite/gcc.dg/c11-unproto-2.c
Normal file
@ -0,0 +1,21 @@
|
||||
/* Test compatibility of unprototyped and prototyped function types (C2x makes
|
||||
the case of types affected by default argument promotions compatible). Test
|
||||
invalid-in-C2x usages, in C11 mode. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c11 -pedantic-errors" } */
|
||||
|
||||
void f1 (); /* { dg-message "previous declaration" } */
|
||||
void f1 (int, ...); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f2 (int, ...); /* { dg-message "previous declaration" } */
|
||||
void f2 (); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f3 (); /* { dg-message "previous declaration" } */
|
||||
void f3 (char, ...); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f4 (char, ...); /* { dg-message "previous declaration" } */
|
||||
void f4 (); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
20
gcc/testsuite/gcc.dg/c2x-unproto-1.c
Normal file
20
gcc/testsuite/gcc.dg/c2x-unproto-1.c
Normal file
@ -0,0 +1,20 @@
|
||||
/* Test compatibility of unprototyped and prototyped function types (C2x makes
|
||||
the case of types affected by default argument promotions compatible). Test
|
||||
valid-in-C2x usages. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c2x -pedantic-errors" } */
|
||||
|
||||
void f1 ();
|
||||
void f1 (float);
|
||||
|
||||
void f2 (float);
|
||||
void f2 ();
|
||||
|
||||
void f3 ();
|
||||
void f3 (char);
|
||||
|
||||
void f4 (char);
|
||||
void f4 ();
|
||||
|
||||
/* Built-in function case. */
|
||||
float sqrtf ();
|
21
gcc/testsuite/gcc.dg/c2x-unproto-2.c
Normal file
21
gcc/testsuite/gcc.dg/c2x-unproto-2.c
Normal file
@ -0,0 +1,21 @@
|
||||
/* Test compatibility of unprototyped and prototyped function types (C2x makes
|
||||
the case of types affected by default argument promotions compatible). Test
|
||||
invalid-in-C2x usages. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=c2x -pedantic-errors" } */
|
||||
|
||||
void f1 (); /* { dg-message "previous declaration" } */
|
||||
void f1 (int, ...); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f2 (int, ...); /* { dg-message "previous declaration" } */
|
||||
void f2 (); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f3 (); /* { dg-message "previous declaration" } */
|
||||
void f3 (char, ...); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
||||
|
||||
void f4 (char, ...); /* { dg-message "previous declaration" } */
|
||||
void f4 (); /* { dg-error "conflicting types" } */
|
||||
/* { dg-message "ellipsis" "" { target *-*-* } .-1 } */
|
Loading…
Reference in New Issue
Block a user