8

In this snippet, a pointer to VLA is used for easier access to a big lookup table :

#pragma GCC diagnostic warning "-Wcast-qual"

char
lookup(int a, int b, int c, char const *raw, int x, int y, int z)
{
    typedef char const (*DATA_PTR)[a][b][c];

    DATA_PTR data = (DATA_PTR)raw;

    return (*data)[x][y][z];
}

GCC 6.2.0 chokes on it while Clang 4.0.0(trunk) compiles just fine, both with -Wcast-qual enabled.

In function 'lookup':
warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual]
   DATA_PTR data = (DATA_PTR)raw;
                   ^

The code runs as expected either way.

My guess is GCC confuses a "pointer to VLA of const elements" and "pointer to const VLA" but I'm reaching ...

Is there a way to shut up GCC without fiddling with warnings ? Is this a GCC bug ?

EDIT1:

Details on the actual code :

struct table {
    int a;
    int b;
    int c;
    char *raw;
};

char
lookup2(struct table const *table, int x, int y, int z)
{
    typedef char const(*DATA_PTR)[table->a][table->b][table->c];

    DATA_PTR data;
    data = (DATA_PTR)table->raw; // GCC ok
    data = (DATA_PTR)(char const *)table->raw; // GCC raises -Wcast-qual

    return (*data)[x][y][z];
}

EDIT2:

So there it is ... the C11 standard draft says in 6.7.3/9 :

If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.

See @hvd answer.

One hack to silence -Wcast-qual :

    DATA_PTR data = (DATA_PTR)(intptr_t)raw;
diapir
  • 2,872
  • 1
  • 19
  • 26
  • 3
    "pointer to VLA of const elements" and "pointer to const VLA" are the same thing. A const array is an array of const elements. Seems like a bug. – Emil Laine Dec 30 '16 at 21:28
  • Why not make the whole thing a bit more type safe, and make `raw` into `char const (*raw)[a][b][c]`? – StoryTeller - Unslander Monica Dec 30 '16 at 21:31
  • @StoryTeller I added what the code might look like but still, that `-Wcast-qual` is weird. – diapir Dec 30 '16 at 22:33
  • @StoryTeller That's a relief, thanks. Feel free to add your comment as an answer so I can close the question. Cheers ! – diapir Dec 30 '16 at 22:50
  • @diapir - It isn't fixed in GCC 6.3 either. Apparently `-Wall -Wextra -pedantic` doesn't turn on `-Wcast-qual` (sigh) – StoryTeller - Unslander Monica Dec 30 '16 at 22:57
  • the posted code is returning a`char `, rather than a `const char ` so the compiler (in this case `gcc` throws away the `const` in the statement: `typedef char const (*DATA_PTR)[a][b][c];` and in the function signature – user3629249 Dec 31 '16 at 08:37

1 Answers1

7

This is a long-standing issue in C. It's the same reason why

int array[2];
const int (*ptr)[2] = &array;

is invalid in C (but would be valid in C++): this declares a pointer to an array of const-qualified integers, which is not a const-qualified array of integers, so the normal rule that a pointer to an type can be implicitly converted to a pointer to the const-qualified version of that type does not apply.

In your case, you're converting from const char * (a pointer to a const-qualified type) to char const (*)[a][b][c] (a pointer to a non-const-qualified type), which -Wcast-qual is supposed to warn about.

clang just never bothered to implement this particular oddity of C, it treats C code with the C++ semantics, which say that an array of const elements is itself const-qualified as well.

You'd normally be able to work around it by wrapping the array in a struct:

typedef struct { char d[a][b][c]; } const *DATA_PTR;

but this is not an option for VLAs. I do not believe there is a suitable workaround other than not using multi-dimensional arrays at all here, or not using -Wcast-qual.

  • Fiddling with warnings it is then ... Are you aware of instances where using the C++ rule in C (like clang) could potentially be dangerous ? There's no reason for it in the standard : _6.7.3.9 If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type._ – diapir Dec 30 '16 at 23:43
  • 1
    @diapir The C++ rule is safe as far as `const`-correctness goes and it has been proposed for C as well (though I do not know of its status). The only risk if you use it now is that you might accidentally write invalid/not-yet-valid C code that then causes an error when a strict C compiler gets used. –  Dec 30 '16 at 23:46