The program is well-formed as far as I can see.
According to [temp.param]/8 the template parameter actually has type const int*, not const int[].
A non-type template-parameter of type “array of T” or “function returning T” is adjusted to be of type
“pointer to T” or “pointer to function returning T”, respectively.
According to [temp.arg.nontype]/1, we can use the name of a complete array object with static storage duration and external linkage as an argument to such a template parameter:
A template-argument for a non-type, non-template template-parameter shall be one of:
...
— a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage or a function with external or internal linkage, including function
templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, where the id-expression is the name of an object or function, except that the
& may be omitted if the name refers to a function or array and shall be omitted if the corresponding
template-parameter is a reference ...
arr is a constant expression, despite the fact that MSVC thinks it isn't. It is a core constant expression according to [expr.const]/2 since it does not contain any forbidden evaluations, and it is a constant expression since it points to an object with static storage duration ([expr.const]/4).
Because the template parameter refers to an array with static storage duration, the bounds of the array are known at the time of template instantiation. It can therefore verify that the access to arr[0] is a legitimate core constant expression since it has well-defined behaviour and falls into the category of allowed lvalue-to-rvalue conversions in [expr.const]/2:
... a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with
a preceding initialization, initialized with a constant expression
arr[]witharr[1]?