Потому что это законный C++.
Вы можете попытаться разыменовать любой указатель, даже если он не выделен вашей программой, вы можете попытаться получить доступ к любой ячейке массива, даже если это вне пределов, законность выражения не зависит от значений переменных, участвующих в этом выражении.
Компилятор не должен запускать какой-либо статический анализ, чтобы проверить, действительно ли вы будете вызывать неопределенное поведение или нет, и не должен компилироваться, если он предполагает, что вы это сделаете (даже если это очевидно, что вы это сделаете).
Проблема в том, что вы не можете проверить доступ к любому доступному массиву во время компиляции (это было бы слишком дорого), поэтому вам придется произвольно нарисовать строку где-нибудь (проблема заключается в слове «произвольно», что не будет хорошо соответствовать стандарту).
Следовательно, проверка того, что вы не будете вызывать неопределенное поведение, - это ответственность программиста (или конкретных инструментов статического анализа).
Зачем? Компилятор не дает двух криков, хотите ли вы стрелять в ногу. * Вы * решили использовать * неопределенное поведение *. Что посеешь то и пожнешь. Если это сработает, вам повезло. – WhozCraig
С clang есть предупреждение, называемое array-bounds, которое делает именно это. –