Bug 81631 - -Wcast-qual false positive for pointer to array
Summary: -Wcast-qual false positive for pointer to array
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 7.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2017-07-31 11:03 UTC by Tobias Jordan
Modified: 2017-09-14 07:45 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2017-09-11 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Jordan 2017-07-31 11:03:59 UTC
Hi,

------
typedef int footype[6];

extern void const * bar;

void baz(void)
{
  footype const * x;
  x = (footype const *) bar;
}
------

with -Wcast-qual, this yields

------
$ gcc -Wcast-qual -c foo.c
foo.c:12:7: warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual]
   x = (footype const *) bar;
       ^
------

If "footype" is any other type than an array, I don't get the warning. I tested gcc 4.5.1, 6.3.0, 7.1.0, on cygwin and Debian, all show this behavior. clang doesn't warn.
Comment 1 Martin Liška 2017-09-11 18:42:01 UTC
Marek can you please take a look?
Comment 2 Marek Polacek 2017-09-13 13:53:12 UTC
This is

void
baz (const int *y)
{
  const int (*x)[6];
  x = (const int (*)[6]) y;
}

ISO C11 says "If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type." so the compiler sees pointer-to-const being casted to pointer-to-array-of-const-ints.  But you can't assign to an array anyway so perhaps it makes sense to not warn in this case.
Comment 3 Tobias Jordan 2017-09-14 07:45:36 UTC
Hi,

thanks for taking a look, and thanks for your explanation. As far as I understand it, it's somewhat intuitive that the qualifiers apply to array elements and not the array type itself. What bugs me is that -Wcast-qual in this case looks at the array type, not at the element type, to detect whether qualifiers match.

My actual use case is more complicated than the first example. I'm doing some kind of marshalling/unmarshalling:

const int (*bar(const int (*x)[6]))[6]
{
  const void * y = x;           /* (1) */
  /* y takes a journey... */
  return (const int (*)[6]) y;  /* (2) */
}

In this example, if I remove the "const" in (1), I get a warning for "-Wdiscarded-array-qualifiers". If I make y a "const void *", I get the "-Wcast-qual" warning in (2). In my opinion, using a "const void *" would be the correct way to do it.

Actually, when I change the type of y to a "void*" and do an explicit cast in (1), like in
  void * y = (void *) x;        /* (1') */

I don't get any warning at all. Here, I would expect a "-Wcast-qual" warning: before the cast, x is a pointer to an array of consts, so I couldn't modify the pointer target. After the cast, I can, and don't get any warnings (but undefined behaviour).

So my proposal for -Wcast-qual would be: when looking at pointer-to-array, consider the qualifiers of the element type, not the array type, to detect whether qualifiers match.

As a side note, clang seems to agree with me here:

$ clang -Wcast-qual -c foo.c
foo.c:3:24: warning: cast from 'int const (*)[6]' to 'void *' drops const qualifier [-Wcast-qual]
   void * y = (void *) x;        /* (1') */
                       ^
1 warning generated.