5

Consider the follow code, which arose from this question:

const int (*foo(const char *a))[1]
    { return (const int (*)[1]) a; }

When compiled with GCC 8.2 (and older versions) using -Wcast-qual, GCC warns:

source>:2:15: warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual]
      { return (const int (*)[1]) a; }
               ^

Is this warning correct? Clearly the destination type has a const qualifier in it.

It is on the element type rather than on the thing immediately pointed to by the pointer, which is the array type. However, the warning remains even if we use typedef int T[1]; and replace the cast with (const T *). Additionally, per C 2018 6.7.3 10, qualifiers on an array type apply to the element type, not the array type, so the type is the same either way.

Clang does not show this warning.

If we change the cast to (const void *):

const int (*foo(const char *a))[1]
    { return (const void *) a; }

then the warning vanishes. If we add -pedantic to the compilation switches, we get a different warning about const:

source>:2:15: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
      { return (const void *) a; }
               ^~~~~~~~~~~~~~~~

This looks like the same warning except it is about the implied conversion from the return expression to the function return type, whereas the previous warning was about the explicit conversion in the cast. But this one appears only with -pedantic. Why?

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Looks like a gcc bug to me? Here's a version with a typedef for the return type that still shows the issue: https://godbolt.org/z/mC8qS6 – zneak Feb 03 '19 at 21:47
  • *pointer to array of const int* and *pointer to const char* -- should be convertible IMO. Seems like a bug to me. – Ajay Brahmakshatriya Feb 03 '19 at 21:48
  • 1
    Pure speculation: it may be that you nailed down the issue in your question with "qualifiers on an array type apply to the element type." It's possible that GCC sees "pointer to (const char)" to "pointer to (array of (const int))", sees that the thing that is being pointed to isn't const, an emits a warning (when in fact it would still be const if it cared to peel one level deeper). – zneak Feb 03 '19 at 21:52
  • 1
    Note: Changes from pointers to `char` to `int` invoke alignment concerns. – chux - Reinstate Monica Feb 03 '19 at 21:56
  • 2
    If you wanted to test my hypothesis, this warning is generated in `handle_warn_cast_qual` of gcc/c/c-typeck.c, at the two lines that say `discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) & ~TYPE_QUALS_NO_ADDR_SPACE (in_type));`. You'd have to dig in `in_otype` to see if it's an array type, and if the element type has its `base.readonly_flag` bit set. – zneak Feb 03 '19 at 22:05
  • Do you receive the same waring with `const int (*foo2(void))[1] { static const char *a = ""; return (const int (*)[1]) a; }`? – chux - Reinstate Monica Feb 03 '19 at 22:05
  • @chux: Yess, GCC warns about the cast. I do not have GCC installed locally. You can use [godbolt.org](https://godbolt.org) to test it the same way I do. – Eric Postpischil Feb 03 '19 at 22:10
  • 4
    Casting `const` away with `(int (*)[1])(const int(*)[1])42;` or even `typedef int T[1]; (T*)(const T*)42;` gives no warning on both gcc and clang. – KamilCuk Feb 03 '19 at 22:29
  • gcc 8.2 does not produce the warning if running on redhat. Neither does 8.1, nor some earlier versions. Wherever you run, it looks like a gcc bug on a particular platform. For the last one it produces `error: invalid conversion from 'const void*' to 'const int (*)[1]' [-fpermissive]` (if you keep function declaration intact), no matter of qualifiers, or compiles without errors (if change function declaration). – Serge Feb 04 '19 at 14:32
  • Slightly simpler code to give the same error: `int main(void) { const char *a = 0; (const int (*)[1])(a); }` – M.M Feb 05 '19 at 00:48
  • @M.M: If we are golfing, `const int (*p)[] = (const void *) 0;`, although GCC for some reason needs `-pedantic` for that one. – Eric Postpischil Feb 05 '19 at 00:58

1 Answers1

4

This is GCC bug 81631. GCC fails to recognize the cast to a pointer to an array retains the const qualifier, due to complications with qualifiers applied to an array actually applying to the array elements.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312