Aviso estranho em uma função C const argumento de matriz multidimensional

Estou recebendo alguns avisos estranhos sobre esse código:

typedef double mat4[4][4];

void mprod4(mat4 r, const mat4 a, const mat4 b)
{
/* yes, function is empty */
}

int main()
{
    mat4 mr, ma, mb;
    mprod4(mr, ma, mb);
}

gcc saída da seguinte forma:

$ gcc -o test test.c
test.c: In function 'main':
test.c:13: warning: passing argument 2 of 'mprod4' from incompatible pointer
type
test.c:4: note: expected 'const double (*)[4]' but argument is of type 'double
(*)[4]'
test.c:13: warning: passing argument 3 of 'mprod4' from incompatible pointer
type
test.c:4:
note: expected 'const double (*)[4]' but argument is of type 'double
(*)[4]'

Se eu definir a função como:

void mprod4(mat4 r, mat4 a, mat4 b)
{
}

Ou definindo matrizes em main como:

mat4 mr;
const mat4 ma;
const mat4 mb;

Ou chame a função em main como:

mprod4(mr, (const double(*)[4])ma, (const double(*)[4])mb);

Ou mesmo definindomat4 Como:

typedef double mat4[16];

Faz o aviso desaparecer. O que esta acontecendo aqui? Estou fazendo algo inválido?

A versão do gcc é 4.4.3, se relevante.

Também publiquei no gcc bugzilla:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47143

Minha solução atual é criar macros feias que lançam coisas para mim:

#ifndef _NO_UGLY_MATRIX_MACROS

#define mprod4(r, a, b) mprod4(r, (const double(*)[4])a, (const double(*)[4])b)

#endif

Resposta de Joseph S. Myers no gcc bugzilla:

Não é um bug. Os parâmetros de função são do tipo "ponteiro para o array [4] de const double" porque const em um tipo de array se aplica ao tipo de elemento, recursivamente, e depois ao tipo de array mais externo, apenas, de um parâmetro do tipo de array decai para um ponteiro , e os argumentos passados são do tipo "ponteiro para o array [4] de duplo" após decaimento do array para o ponteiro, e o único caso em que os qualificadores podem ser adicionados à atribuição, passagem de argumentos etc. são qualificadores no ponteiro imediato alvo, não aqueles aninhados mais profundamente.

Parece bastante confuso para mim, como a função espera:

pointer to array[4] of const doubles

e nós estamos passando

pointer to const array[4] of doubles

intead.

Ou seria o inverso? Os avisos sugerem que a função espera a:

const double (*)[4]

o que me parece mais um

pointer to const array[4] of doubles

Estou realmente confuso com esta resposta. Alguém que entenda o que ele disse pode esclarecer e exemplificar?