From cc806126215c3f4dc187eff3bf923458d8cc6b4f Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 29 Apr 2021 00:50:35 +0000 Subject: [PATCH] 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. --- gcc/c/c-typeck.c | 4 ++-- gcc/testsuite/gcc.dg/c11-unproto-1.c | 24 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c11-unproto-2.c | 21 +++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-unproto-1.c | 20 ++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-unproto-2.c | 21 +++++++++++++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c11-unproto-1.c create mode 100644 gcc/testsuite/gcc.dg/c11-unproto-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-unproto-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-unproto-2.c diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 51a62c800f7..3b45cfda0ff 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -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), diff --git a/gcc/testsuite/gcc.dg/c11-unproto-1.c b/gcc/testsuite/gcc.dg/c11-unproto-1.c new file mode 100644 index 00000000000..ea9e807a68e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-unproto-1.c @@ -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" } */ diff --git a/gcc/testsuite/gcc.dg/c11-unproto-2.c b/gcc/testsuite/gcc.dg/c11-unproto-2.c new file mode 100644 index 00000000000..0557ae3f5cb --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-unproto-2.c @@ -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 } */ diff --git a/gcc/testsuite/gcc.dg/c2x-unproto-1.c b/gcc/testsuite/gcc.dg/c2x-unproto-1.c new file mode 100644 index 00000000000..45d68f2c292 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-unproto-1.c @@ -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 (); diff --git a/gcc/testsuite/gcc.dg/c2x-unproto-2.c b/gcc/testsuite/gcc.dg/c2x-unproto-2.c new file mode 100644 index 00000000000..f826b7c3ac8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-unproto-2.c @@ -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 } */