Cast "pointer to const" to "pointer to const VLA"

445 views Asked by At

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;
1

There are 1 answers

2
AudioBubble On BEST ANSWER

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.