Каковы правила конвертации указателя на массив неопределенной длины в указатель на массив определенной длины?
С++ - язык более высокого уровня, тут компилятор не позволит вам выстрелить себе в ногу неявным приведением сена к соломе. Нужно объявить его явно.
static_cast - если компилятор готов согласиться с вами, что одно можно просто привести к другому во время компиляции.
dynamic_cast - если вы приводите указатель на родительский класс к указателю на дочерний
и reinterpret_cast - если вы приводите по-сишному, "ногой в дверь", уверены в себе и не нуждаетесь в подсказках компилятора насчет того, что делаете.
В выражении p = p2 мы выполняем неявное преобразование встроенных типов, для которых в стандарте не описаны правила преобразования. То есть такое преобразование не гарантировано, но может быть реализовано компилятором, например
#include <type_traits>
using namespace std;

int main() {
    static_assert(std::is_convertible<int(*)[2], int(*)[]>::value, "Non-convertible");
    return 0;
}
компилируется в gcc 12.2, в clang 15.0 - ошибка.

Существует старое не принятое предложение о закреплении такого преобразования стандартом.