diff mbox series

[committed] c: C2x changes to function type compatibility

Message ID alpine.DEB.2.22.394.2104290051170.115529@digraph.polyomino.org.uk
State New
Headers show
Series [committed] c: C2x changes to function type compatibility | expand

Commit Message

Joseph Myers April 29, 2021, 12:51 a.m. UTC
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.
diff mbox series

Patch

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