c: Give errors more consistently for void parameters [PR114816]

Cases of void parameters, other than a parameter list of (void) (or
equivalent with a typedef for void) in its entirety, have been made a
constraint violation in C2Y (N3344 alternative 1 was adopted), as part
of a series of changes to eliminate unnecessary undefined behavior by
turning it into constraint violations, implementation-defined behavior
or something else with stricter bounds on what behavior is allowed.
Previously, these were implicitly undefined behavior (see DR#295),
with only some cases listed in Annex J as undefined (but even those
cases not having wording in the normative text to make them explicitly
undefined).

As discussed in bug 114816, GCC is not entirely consistent about
diagnosing such usages; unnamed void parameters get errors when not
the entire parameter list, while qualified and register void (the
cases listed in Annex J) get errors as a single unnamed parameter, but
named void parameters are accepted with a warning (in a declaration
that's not a definition; it's not possible to define a function with
incomplete parameter types).

Following C2Y, make all these cases into errors.  The errors are not
conditional on the standard version, given that this was previously
implicit undefined behavior.  Since it wasn't possible anyway to
define such functions, only declare them without defining them (or
otherwise use such parameters in function type names that can't
correspond to any defined function), hopefully the risks of
compatibility issues are small.

Bootstrapped with no regressions for x86-64-pc-linux-gnu.

	PR c/114816

gcc/c/
	* c-decl.cc (grokparms): Do not warn for void parameter type here.
	(get_parm_info): Give errors for void parameters even when named.

gcc/testsuite/
	* gcc.dg/c2y-void-parm-1.c: New test.
	* gcc.dg/noncompile/920616-2.c, gcc.dg/noncompile/921116-1.c,
	gcc.dg/parm-incomplete-1.c: Update expected diagnostics.
This commit is contained in:
Joseph Myers 2024-11-21 21:46:00 +00:00
parent 4574f15bb3
commit 338d687e2a
5 changed files with 163 additions and 20 deletions

View File

@ -8480,8 +8480,8 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
or definition of the function. In the case where the tag was
first declared within the parameter list, a warning has
already been given. If a parameter has void type, then
however the function cannot be defined or called, so
warn. */
this has already received an error (constraint violation in C2Y,
previously implicitly undefined behavior). */
for (parm = arg_info->parms, typelt = arg_types, parmno = 1;
parm;
@ -8508,17 +8508,6 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
TREE_TYPE (parm) = error_mark_node;
arg_types = NULL_TREE;
}
else if (VOID_TYPE_P (type))
{
if (DECL_NAME (parm))
warning_at (input_location, 0,
"parameter %u (%q+D) has void type",
parmno, parm);
else
warning_at (DECL_SOURCE_LOCATION (parm), 0,
"parameter %u has void type",
parmno);
}
}
if (DECL_NAME (parm) && TREE_USED (parm))
@ -8627,12 +8616,14 @@ get_parm_info (bool ellipsis, tree expr)
if (TREE_ASM_WRITTEN (decl))
error_at (b->locus,
"parameter %q+D has just a forward declaration", decl);
/* Check for (..., void, ...) and issue an error. */
else if (VOID_TYPE_P (type) && !DECL_NAME (decl))
/* Check for (..., void, ...) and named void parameters and issue an
error. */
else if (VOID_TYPE_P (type))
{
if (!gave_void_only_once_err)
{
error_at (b->locus, "%<void%> must be the only parameter");
error_at (b->locus,
"%<void%> must be the only parameter and unnamed");
gave_void_only_once_err = true;
}
}

View File

@ -0,0 +1,152 @@
/* Test errors for void parameters (constraint violation in C2Y, previously
implicit undefined behavior; bug 114816). */
/* { dg-do compile } */
/* { dg-options "-std=c2y -pedantic-errors" } */
typedef void Void;
typedef const void CVoid;
typedef volatile void VVoid;
/* Valid cases. */
void f1 (void);
void f2 (Void);
void df1 (void) {}
void df2 (Void) {}
/* All other variants are invalid. */
void g1 (const void); /* { dg-error "void" } */
void g2 (CVoid); /* { dg-error "void" } */
void g3 (volatile void); /* { dg-error "void" } */
void g4 (VVoid); /* { dg-error "void" } */
void g5 (register void); /* { dg-error "void" } */
void g6 (register Void); /* { dg-error "void" } */
void h1 (void x); /* { dg-error "void" } */
void h2 (Void x); /* { dg-error "void" } */
void h3 (const void x); /* { dg-error "void" } */
void h4 (CVoid x); /* { dg-error "void" } */
void h5 (volatile void x); /* { dg-error "void" } */
void h6 (VVoid x); /* { dg-error "void" } */
void h7 (register void x); /* { dg-error "void" } */
void h8 (register Void x); /* { dg-error "void" } */
void i1 (void, ...); /* { dg-error "void" } */
void i2 (Void, ...); /* { dg-error "void" } */
void i3 (const void, ...); /* { dg-error "void" } */
void i4 (CVoid, ...); /* { dg-error "void" } */
void i5 (volatile void, ...); /* { dg-error "void" } */
void i6 (VVoid, ...); /* { dg-error "void" } */
void i7 (register void, ...); /* { dg-error "void" } */
void i8 (register Void, ...); /* { dg-error "void" } */
void j1 (void x, ...); /* { dg-error "void" } */
void j2 (Void x, ...); /* { dg-error "void" } */
void j3 (const void x, ...); /* { dg-error "void" } */
void j4 (CVoid x, ...); /* { dg-error "void" } */
void j5 (volatile void x, ...); /* { dg-error "void" } */
void j6 (VVoid x, ...); /* { dg-error "void" } */
void j7 (register void x, ...); /* { dg-error "void" } */
void j8 (register Void x, ...); /* { dg-error "void" } */
void k1 (int i, void); /* { dg-error "void" } */
void k2 (int i, Void); /* { dg-error "void" } */
void k3 (int i, const void); /* { dg-error "void" } */
void k4 (int i, CVoid); /* { dg-error "void" } */
void k5 (int i, volatile void); /* { dg-error "void" } */
void k6 (int i, VVoid); /* { dg-error "void" } */
void k7 (int i, register void); /* { dg-error "void" } */
void k8 (int i, register Void); /* { dg-error "void" } */
void k9 (int i, void x); /* { dg-error "void" } */
void k10 (int i, Void x); /* { dg-error "void" } */
void k11 (int i, const void x); /* { dg-error "void" } */
void k12 (int i, CVoid x); /* { dg-error "void" } */
void k13 (int i, volatile void x); /* { dg-error "void" } */
void k14 (int i, VVoid x); /* { dg-error "void" } */
void k15 (int i, register void x); /* { dg-error "void" } */
void k16 (int i, register Void x); /* { dg-error "void" } */
void l1 (void, int i); /* { dg-error "void" } */
void l2 (Void, int i); /* { dg-error "void" } */
void l3 (const void, int i); /* { dg-error "void" } */
void l4 (CVoid, int i); /* { dg-error "void" } */
void l5 (volatile void, int i); /* { dg-error "void" } */
void l6 (VVoid, int i); /* { dg-error "void" } */
void l7 (register void, int i); /* { dg-error "void" } */
void l8 (register Void, int i); /* { dg-error "void" } */
void l9 (void x, int i); /* { dg-error "void" } */
void l10 (Void x, int i); /* { dg-error "void" } */
void l11 (const void x, int i); /* { dg-error "void" } */
void l12 (CVoid x, int i); /* { dg-error "void" } */
void l13 (volatile void x, int i); /* { dg-error "void" } */
void l14 (VVoid x, int i); /* { dg-error "void" } */
void l15 (register void x, int i); /* { dg-error "void" } */
void l16 (register Void x, int i); /* { dg-error "void" } */
void dg1 (const void) {} /* { dg-error "void|incomplete" } */
void dg2 (CVoid) {} /* { dg-error "void|incomplete" } */
void dg3 (volatile void) {} /* { dg-error "void|incomplete" } */
void dg4 (VVoid) {} /* { dg-error "void|incomplete" } */
void dg5 (register void) {} /* { dg-error "void|incomplete" } */
void dg6 (register Void) {} /* { dg-error "void|incomplete" } */
void dh1 (void x) {} /* { dg-error "void|incomplete" } */
void dh2 (Void x) {} /* { dg-error "void|incomplete" } */
void dh3 (const void x) {} /* { dg-error "void|incomplete" } */
void dh4 (CVoid x) {} /* { dg-error "void|incomplete" } */
void dh5 (volatile void x) {} /* { dg-error "void|incomplete" } */
void dh6 (VVoid x) {} /* { dg-error "void|incomplete" } */
void dh7 (register void x) {} /* { dg-error "void|incomplete" } */
void dh8 (register Void x) {} /* { dg-error "void|incomplete" } */
void di1 (void, ...) {} /* { dg-error "void|incomplete" } */
void di2 (Void, ...) {} /* { dg-error "void|incomplete" } */
void di3 (const void, ...) {} /* { dg-error "void|incomplete" } */
void di4 (CVoid, ...) {} /* { dg-error "void|incomplete" } */
void di5 (volatile void, ...) {} /* { dg-error "void|incomplete" } */
void di6 (VVoid, ...) {} /* { dg-error "void|incomplete" } */
void di7 (register void, ...) {} /* { dg-error "void|incomplete" } */
void di8 (register Void, ...) {} /* { dg-error "void|incomplete" } */
void dj1 (void x, ...) {} /* { dg-error "void|incomplete" } */
void dj2 (Void x, ...) {} /* { dg-error "void|incomplete" } */
void dj3 (const void x, ...) {} /* { dg-error "void|incomplete" } */
void dj4 (CVoid x, ...) {} /* { dg-error "void|incomplete" } */
void dj5 (volatile void x, ...) {} /* { dg-error "void|incomplete" } */
void dj6 (VVoid x, ...) {} /* { dg-error "void|incomplete" } */
void dj7 (register void x, ...) {} /* { dg-error "void|incomplete" } */
void dj8 (register Void x, ...) {} /* { dg-error "void|incomplete" } */
void dk1 (int i, void) {} /* { dg-error "void|incomplete" } */
void dk2 (int i, Void) {} /* { dg-error "void|incomplete" } */
void dk3 (int i, const void) {} /* { dg-error "void|incomplete" } */
void dk4 (int i, CVoid) {} /* { dg-error "void|incomplete" } */
void dk5 (int i, volatile void) {} /* { dg-error "void|incomplete" } */
void dk6 (int i, VVoid) {} /* { dg-error "void|incomplete" } */
void dk7 (int i, register void) {} /* { dg-error "void|incomplete" } */
void dk8 (int i, register Void) {} /* { dg-error "void|incomplete" } */
void dk9 (int i, void x) {} /* { dg-error "void|incomplete" } */
void dk10 (int i, Void x) {} /* { dg-error "void|incomplete" } */
void dk11 (int i, const void x) {} /* { dg-error "void|incomplete" } */
void dk12 (int i, CVoid x) {} /* { dg-error "void|incomplete" } */
void dk13 (int i, volatile void x) {} /* { dg-error "void|incomplete" } */
void dk14 (int i, VVoid x) {} /* { dg-error "void|incomplete" } */
void dk15 (int i, register void x) {} /* { dg-error "void|incomplete" } */
void dk16 (int i, register Void x) {} /* { dg-error "void|incomplete" } */
void dl1 (void, int i) {} /* { dg-error "void|incomplete" } */
void dl2 (Void, int i) {} /* { dg-error "void|incomplete" } */
void dl3 (const void, int i) {} /* { dg-error "void|incomplete" } */
void dl4 (CVoid, int i) {} /* { dg-error "void|incomplete" } */
void dl5 (volatile void, int i) {} /* { dg-error "void|incomplete" } */
void dl6 (VVoid, int i) {} /* { dg-error "void|incomplete" } */
void dl7 (register void, int i) {} /* { dg-error "void|incomplete" } */
void dl8 (register Void, int i) {} /* { dg-error "void|incomplete" } */
void dl9 (void x, int i) {} /* { dg-error "void|incomplete" } */
void dl10 (Void x, int i) {} /* { dg-error "void|incomplete" } */
void dl11 (const void x, int i) {} /* { dg-error "void|incomplete" } */
void dl12 (CVoid x, int i) {} /* { dg-error "void|incomplete" } */
void dl13 (volatile void x, int i) {} /* { dg-error "void|incomplete" } */
void dl14 (VVoid x, int i) {} /* { dg-error "void|incomplete" } */
void dl15 (register void x, int i) {} /* { dg-error "void|incomplete" } */
void dl16 (register Void x, int i) {} /* { dg-error "void|incomplete" } */

View File

@ -1 +1 @@
void f(void a,...){} /* { dg-error "has incomplete type" } */
void f(void a,...){} /* { dg-error "void|has incomplete type" } */

View File

@ -1 +1 @@
void a (void x) {} /* { dg-error "has incomplete type" } */
void a (void x) {} /* { dg-error "void|has incomplete type" } */

View File

@ -22,6 +22,6 @@ union u;
void v(union u x) { } /* { dg-error "parameter 1 \\('x'\\) has incomplete type" } */
void p(void x); /* { dg-warning "parameter 1 \\('x'\\) has void type" } */
void p(void x); /* { dg-error "'void' must be the only parameter and unnamed" } */
void q(const void x); /* { dg-warning "parameter 1 \\('x'\\) has void type" } */
void q(const void x); /* { dg-error "'void' must be the only parameter and unnamed" } */