Bug 16602 - Spurious warnings about pointer to array -> const pointer to array conversion
Summary: Spurious warnings about pointer to array -> const pointer to array conversion
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.0.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 33076 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-07-17 07:50 UTC by Jozef Behran
Modified: 2014-03-27 12:14 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jozef Behran 2004-07-17 07:50:45 UTC
/* 
  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. 
*/
Comment 1 Andrew Pinski 2004-07-17 08:49:48 UTC
Note arrays do not get type quals at all so this is a correct warning.
Comment 2 Andreas Schwab 2007-09-19 09:47:40 UTC
*** Bug 33076 has been marked as a duplicate of this bug. ***
Comment 3 Paolo Bonzini 2007-09-19 11:46:21 UTC
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.
Comment 4 Ken Raeburn 2007-09-19 17:27:15 UTC
(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?
Comment 5 Jozef Behran 2007-09-26 11:58:20 UTC
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.
Comment 6 Joseph S. Myers 2007-09-26 12:09:54 UTC
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.
Comment 7 Jozef Behran 2007-09-26 12:33:25 UTC
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.
Comment 8 Andrew Pinski 2007-09-26 16:40:43 UTC
Again this is invalid.
Comment 9 Ilguiz Latypov 2010-03-12 03:49:37 UTC
(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
}

Comment 10 Ilguiz Latypov 2010-03-15 19:47:04 UTC
(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
Comment 11 Sebastian Unger 2014-02-13 01:22:06 UTC
(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.
Comment 12 Andrew Pinski 2014-02-13 01:52:26 UTC
(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)
Comment 13 Sebastian Unger 2014-02-13 02:03:07 UTC
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);
}
Comment 14 Sebastian Unger 2014-02-26 01:39:00 UTC
So how do I go about re-opening this? Or should I raise a new one?
Comment 15 Andrew Pinski 2014-02-26 01:53:54 UTC
(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).
Comment 16 jsm-csl@polyomino.org.uk 2014-02-26 01:56:53 UTC
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.
Comment 17 Sebastian Unger 2014-02-26 02:00:13 UTC
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.