/* This piece of code will trigger the warning "passing arg 1 of `name' from incompatible pointer type" on lines 24, 25 and 26, but it should not, because the pointers are in fact compatible. To prove the compatibility comment out the "[8]" at line 9 and recompile; the warnings will disappear. The warnings also disappear if the "const" from the OSHSAddrToBinIPv4() declaration is removed; I guess that the "const" is doing problems. */ typedef int THostAddr[8]; typedef struct { char Command; THostAddr Host; int Port; } TOpenTCPClientCommand; static void OSHSAddrToBinIPv4(const THostAddr *Host) { THostAddr *MyHost; TOpenTCPClientCommand P; TOpenTCPClientCommand *Packet; OSHSAddrToBinIPv4(MyHost); OSHSAddrToBinIPv4(&P.Host); OSHSAddrToBinIPv4(&Packet->Host); } /* - Tested with gcc 3.2.2 on Mandrake GNU/Linux 9.1 ("bamboo") (kernel 2.4.21-0.13mdk) on an i686 - Fails also with gcc 3.5.0 (experimental 17072004) on the same machine - There is no bug when pointers to a structure or union are involved. */
Note arrays do not get type quals at all so this is a correct warning.
*** Bug 33076 has been marked as a duplicate of this bug. ***
I'm not convinced by the explanation in the comment. A pointer to array *is* compatible with the corresponding const pointer type; -Wcast-qual may apply too, but that's not exhibited in the test case.
(In reply to comment #3) > I'm not convinced by the explanation in the comment. A pointer to array *is* > compatible with the corresponding const pointer type; -Wcast-qual may apply > too, but that's not exhibited in the test case. That's what I originally thought, but now (as I explained in a comment to 33076) I think there's a quirk of the standard that makes them not compatible. I'd be happy to be shown to be wrong -- but can you provide specific references to the standard to refute my argument in 33076?
Section 5.6.2.1, paragraph 2 says "E1[E2] is equivalent to *((E1)+(E2))". This means if we have "typedef int THostAddr[8]" then the declaration "THostAddr *Host" declares Host to be a pointer to 8-item arrays of integers, so the "const" in "const THostAddr *Host" must be applied to the whole array type called "THostAddr" and not just the member type of the array type "THostAddr". Also section 6.7.7, paragraph 3 says "typedef" introduces a synonym to a type specified by the specifier. Therefore the element type of the "THostAddr[10]" type is "THostAddr" and not "int" (the element type of "THostAddr"). This meaning is hidden in the words "a typedef declarator does not introduce a new type, only a synonym for the type specified" (this implies "a typedef declarator introduces a synonym for the type specified"). Just to make my point clear: these two array variables don't have the same element type: typedef int THostAddr[8]; THostAddr HostList1[10]; int HostList2[80]; The element type of HostList1 is an 8-item array of ints, while the element type of HostList2 is plain int (so you can write "HostList1[x][y]" but not "HostList2[x][y]"). If you don't believe me, try this little program: --- snip --- #include <stdio.h> typedef int THostAddr[8]; THostAddr HostList1[10]; int HostList2[80]; int main(void) { printf("%d %d\n",sizeof(HostList1[0]),sizeof(HostList2[0])); printf( "%d %d\n", (int *)(HostList1+1)-(int *)HostList1, (int *)(HostList2+1)-(int *)HostList2 ); return(0); } --- snip --- It will say "32 4" on my x86 GNU/Linux box (or maybe some other number on different platforms but the first number will always be 8-times bigger than the second one). So when the *SIZES* of the element types of the two variables don't match, they clearly cannot have the same element type. The conclusion is that you are wrong with the argument in bug 33076. You cannot say the objects that trigger the spurious warnings have "int" as their element type, cause they don't have. Their element type is an array of ints. And then the "const" qualifier must be applied to the whole of this "array of ints" in these examples according to the standard.
When you apply const to "array of int", the resulting type is "array of const int" not "const array of int"; that's how type qualifiers and arrays interact in C, there is no such thing as a qualified array type. "array of const int" is not a const-qualified type in C.
Hm, I must apologize for argumenting about wrong point of this issue. Now I can see why other sometimes say "think before you type" :) The problem here is not whether applying const to "array of int" makes "const array of int" or "array of const int". The problem here is why gcc does not apply that "const" automatically and rather complains about incompatible pointer types. I am reopening the bug cause I still don't have a clue why "pointer to array of ints" typed expression is assignment incompatible with a "pointer to array of const ints" typed lvalue. Especially when "pointer to int" typed expression IS assignment compatible with "pointer to const int" typed lvalue. This is what is this bug all about.
Again this is invalid.
(In reply to comment #7) > I am reopening the bug cause I still don't have a clue why "pointer to array of > ints" typed expression is assignment incompatible with a "pointer to array of > const ints" typed lvalue. Especially when "pointer to int" typed expression IS > assignment compatible with "pointer to const int" typed lvalue. This is what is > this bug all about. Comment #9 to bug 33076 showed me a link explaining how constness of a multiply referenced value cannot be promised, and, therefore, C propagates the compile -time constness requirement up the assignment chain in cases where the level of pointer indirection is greater than 1. http://c-faq.com/ansi/constmismatch.html I came up with a similar example for the "array of const ints". It shows that the const promise might have been violated inside the function if multiply-indirected lvalue constness was relaxed. typedef const int carr_t[8]; typedef int arr_t[8]; void foo(carr_t *carrp) { arr_t *hacker; carr_t **holder = &hacker; // a warning (*holder) = carrp; // "hacker = carrp" in disguise, but both sides are (carr_t *) (*hacker)[ 0 ] = 9; // no warning } void bar(void) { arr_t arr = { 1, 2, 3, 4, 5, 6, 7, 8 }; foo(arr); // a warning }
(In reply to comment #9) > constness of a multiply > referenced value cannot be promised, and, therefore, C propagates the compile > -time constness requirement up the assignment chain in cases where the level of > pointer indirection is greater than 1. The specs mention this case, too. Constraints 1 One of the following shall hold:99) [..] - 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; [..] 6 EXAMPLE 3 Consider the fragment: const char **cpp; char *p; const char c = 'A'; cpp = &p; // constraint violation *cpp = &c; // valid *p = 0; // valid The first assignment is unsafe because it would allow the following valid code to attempt to change the value of the const object c. from section 6.5.16.1 "Simple assignment", n1336.pdf, http://www.open-std.org/jtc1/sc22/wg14/www/projects
(In reply to Joseph S. Myers from comment #6) > When you apply const to "array of int", the resulting type is "array of > const int" not "const array of int"; that's how type qualifiers and arrays > interact in C, there is no such thing as a qualified array type. "array of > const int" is not a const-qualified type in C. Can anybody provide a reference to the standard to the effect of this claim? Because I can't find any, and I do believe this statement is wrong. All other comments claiming this issue to be invalid are based on this (as are all examples claiming to show that the original issue breaks the constness promise). I'm inclined to reopen this issue unless someone can point me to the standard for this.
(In reply to Sebastian Unger from comment #11) > I'm inclined to reopen this issue unless someone can point me to the > standard for this. From 6.7.3/9 (in the C11 draft): If the specification of an array type includes any type qualifiers, the element type is so qualified, not the array type. If the specification of a function type includes any type qualifiers, the behavior is undefined. 136)
I believe the intent behind that is that the qualification of an array type is identical to that of its element type. I.e. the statement here is that an 'array of const ints' is identical to a 'const array of ints' rather than that the latter does not exist. Thus a 'pointer to array of ints' is perfectly convertible to 'pointer to array of const ints' which makes perfect sense. Note that this is completely different from a 'pointer to pointer to int' or any such as has been given in previous examples. At the very least GCC should treat it such in Gnu99 mode, as it makes perfect sense to have the following code compile successfully: typedef int IntArray[3]; void foo(IntArray const* a); void bar(IntArray* a) { foo(a); }
So how do I go about re-opening this? Or should I raise a new one?
(In reply to Sebastian Unger from comment #14) > So how do I go about re-opening this? Or should I raise a new one? Maybe you should raise it in the C standards mailing/news (news:comp.std.c) group as my reading of the standard makes GCC correct. And also this has been part of the standard since C89 (I found it while doing some searching on my quoted part and what others have said about this part of C).
It is *not a bug*, and so should remain closed, and no new bug should be opened. See the explicit "not the array type" wording already quoted.
Well, it is a bug. The question is whether it is a bug in GCC or in the standard. I will raise it in the mailing list as suggested, but GCC could of course again lead the way and implement this as a GNU extension until the standard catches up.