That is not true, and it's not about void *'s "magic". You can also
assign a const char * to a char * and still have a conforming
program.
Only because "conforming program" is a rather loose term. A
conforming program can use non-portable features.
What do you mean by "perfectly conforming"? If you mean the same as
"strictly conforming", I disagree. Here is the code again:
#include <stdio.h>
int foo(void *);
int main(void) {
const char * const p = "hello world";
foo(p);
return 0;
}
int foo(void *p) { return puts(p); }
I'm not up to digging through the standard at the moment, but if you
compile it with "gcc -std=c99 -pedantic-errors" and bugreport the
resulting error message, maybe they'll tell you where to find it
gcc has idiotic and inaccurate warning messages [1] (which btw you
turn into diagnostic errors with -pedantic-errors)
My program is 100% conforming to C99 (and perhaps C89/POSIX too).
Again, what is 100% conforming? It violates a constraint and thus
requires a diagnostic.
6.5.2.2 Function calls
Constraints
...
2 If the expression that denotes the called function has a type that
includes a prototype, the number of arguments shall agree with the
number of parameters. Each argument shall have a type such that its
value may be assigned to an object with the unqualified version of
the type of its corresponding parameter.
I.e. the argument, p, must have a type such that its value may be
assigned to an object of type void *. The correctness of the call is
defined in terms of the correctness of:
const char * const arg = "hello world";
void *param = arg;
So we got to:
6.5.16.1 Simple assignment
Constraints
One of the following shall hold:
— the left operand has qualified or unqualified arithmetic type and
the right has arithmetic type;
— the left operand has a qualified or unqualified version of a
structure or union type compatible with the type of the right;
— both operands are pointers to qualified or unqualified versions of
compatible types, and the type pointed to by the left has all the
qualifiers of the type pointed to by the right;
No to these three.
— one operand is a pointer to an object or incomplete type and the
other is a pointer to a qualified or unqualified version of void,
and the type pointed to by the left has all the qualifiers of the
type pointed to by the right;
No, but this is close. One (arg) is a pointer to an object and the
other (param) is a pointer to an unqualified version of void, but the
type pointed to by the left (void) does not have all the qualifiers of
the type pointed to by the right (const char).
— the left operand is a pointer and the right is a null pointer
constant; or
— the left operand has type _Bool and the right is a pointer.
No for these as well. So gcc is correct in issuing a diagnostic.