A parameter of array type is automatically adjusted to a pointer type.
Therefore a parameter declared as:
int A[3]
is transformed to:
int *A
However, with the array notation there is no intuitive place to add qualifier the variable a itself (not the data pointed by a).
Therefore C standard allows to put those specifier between brackets.
Thus:
void f(int a[const volatile restrict 2])
is actually:
void (int * const volatile restrict a)
The size (2 in above example) is usually ignored. The exception is when static keyword is used. It provides a hint for a compiler that at least elements at addresses a + 0 to a + size - 1 are valid.
This hint in theory should improve optimization by simplifying vectorization. However, AFAIK it is ignored by major compilers.
Your code:
int b[1];
f(b);
is triggering UB because only element at address b + 0 is valid while the hint requires b+0 and b+1 to be valid. Better compilers/sanitizers should detect that.
The static is also useful for self documentation and detection of errors like telling that at least n elements pointed by a pointer must be valid:
void fun(int n, int arr[static n])
or even telling that the pointer is never NULL:
void fun(int ptr[static 1]);
Moreover syntax int buf[static n] is a good visual hint that something is actually not an array. It help to avoid a common error when trying to acquire the a size of "array" with sizeof buf syntax.
EDIT
As stated on the comment the word "hint" may be a bit misleading
because it could be interpreted that violation the "hint" is not
an error though it may result in some non-optimality (like performance degradation).
Actually, it is rather a requirement, violating which results in undefined behavior.