The current implementation works in the following way:
Each forward parameter declaration or parameter declaration
"shadows" previous forward parameter declarations. If array
lengths don't match, the old length is ignored. If the new
declaration doesn't specify a length, the old length is
forgotten.
$ cat cap.c
int
f(int n, char a[][n]; int n, char a[][n+1])
{
return sizeof(a[0]);
}
int
main(void)
{
char a[42];
return f(42, &a);
}
$ gcc cap.c
$ ./a.out; echo $?
43
We don't want to define the behavior to be that. If such a program is
ever written, that's certainly a mistake.
The old documentation said that the types "must match", which clearly
means that the program above would have undefined behavior.
In the future, we should diagnose when array lengths don't match; that
would turn most of these issues into constraint violations. We already
do that for mismatching function prototypes, so we should be able to
diagnose forward declarations within the same function declarator.
On the other hand, "must match" is too strong. The C standard doesn't
say what it means for two types to match. If we interpret it as being
"the same type", which is the most obvious interpretation, it is
unnecessarily strong. One may want to forward declare an array
parameter without specifying its length, and later specify the length in
the parameter declaration. Here's an example I use for a function
similar to stpcpy(3) but which takes a pointer one past the last element
in the destination buffer, to truncate the copy instead of overflowing.
char *
stpecpy(char p[], char end[];
char p[p?end-p:0], char end[0], const char *restrict src);
This code has always worked, regardless of what the documentation says.
This patch changes specification to define the behavior for such code
as, and uses "must be compatible with", to use type compatibility rules,
which require that array lengths be the same, if specified in both
declarations. If array lengths don't match, the behavior is undefined.
If it is only specified in one of them, then the behavior is well
defined, and shadowing rules apply.
We must document this shadowing, because the alternative would be
forming a composite type. But forming a composite type would be
a breaking change, so we should not do that.
gcc/ChangeLog:
* doc/extend.texi (Variable Length): Parameter forward
declarations follow type compatibility rules.
Signed-off-by: Alejandro Colomar <[email protected]>
---
gcc/doc/extend.texi | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index b4879b3d82ff..48166d44546e 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -711,8 +711,15 @@ just like in the regular list of parameter declarations.
You can write any number of lists of parameter forward declaration,
but using more than one is unnecessary.
The last semicolon is followed by the list of parameter declarations.
-Each parameter forward declaration must match
-a parameter declaration in parameter name and data type.
+
+Each parameter forward declaration must
+match a parameter declaration in parameter name
+and must be compatible with its type.
+
+A parameter declaration or forward parameter declaration
+shadows previous declarations of the same identifier
+within that function declarator.
+
ISO C99 does not support parameter forward declarations.
@node Zero Length
Range-diff:
-: ------------ > 1: 2fecf4d86cb3 gcc/doc/extend.texi: Parameter forward
declarations follow type compatibility rules
--
2.51.0