Consider the following (link to compiler explorer: https://godbolt.org/z/jWsxsK) #include <array> static constexpr auto doy = []{ std::array<int, 13> month_offset{}; for (int m=1; m<=12;++m) { month_offset[m] = (153*(m > 2 ? m-3 : m+9) + 2)/5; } return month_offset; }(); auto foo(int m) -> int { #ifdef LOCAL constexpr auto doy = []{ std::array<int, 13> month_offset{}; for (int m=1; m<=12;++m) { month_offset[m] = (153*(m > 2 ? m-3 : m+9) + 2)/5; } return month_offset; }(); #endif return doy[m]; } This is a fragment of code that does some calculation to figure out the date, which isn't super important. If LOCAL is not defined (i.e. we declare the array as a namespace-scope constexpr), the -O3 codegen of 'foo' is: foo(int): movsx rdi, edi mov eax, DWORD PTR doy[0+rdi*4] ret However, if we want to move the declaration of doy to be more local to the calculation and compile with -DLOCAL, the codegen instead is (on -O3): foo(int): pxor xmm0, xmm0 mov rax, QWORD PTR .LC0[rip] movsx rdi, edi mov DWORD PTR [rsp-24], 275 movaps XMMWORD PTR [rsp-72], xmm0 movdqa xmm0, XMMWORD PTR .LC1[rip] mov QWORD PTR [rsp-68], rax movaps XMMWORD PTR [rsp-56], xmm0 movdqa xmm0, XMMWORD PTR .LC2[rip] movaps XMMWORD PTR [rsp-40], xmm0 mov eax, DWORD PTR [rsp-72+rdi*4] ret This can be alleviated by marked the local variable doy as being static constexpr. Except that this prevents 'foo' from being a constexpr function (can't have static variables). This just seems like bad codegen, I'm not sure there's any reason that the compiler needs to do work here. It would be nice if the codegen with a local constexpr variable were the same as if it were a non-local constexpr variable.
I don't see anything wrong on that, the constexpr var is not evaluated at runtime, it has a constant initializer. So in the end it is static const int doy1[] = { 306, 337, 31, 61, 92, 122, 153, 184, 214, 245, 275 }; int foo1(int m) { return doy1[m]; } int foo2(int m) { static const int doy2[] = { 306, 337, 31, 61, 92, 122, 153, 184, 214, 245, 275 }; return doy2[m]; } int foo3(int m) { const int doy3[] = { 306, 337, 31, 61, 92, 122, 153, 184, 214, 245, 275 }; return doy3[m]; } and there is nothing C++ specific on it. The compiler may promote the doy3 variable from automatic variable into static variable if it can prove it is safe to do so (it would be unsafe e.g. if foo3 could be called recursively and compare the addresses of the var between the recursive invocations). GCC does that early (during gimplification) if the variable is not address taken, but the array reference implies address taking. And, especially for the original testcase where operator[] is overloaded, it really can't do better early, so we'd need an optimization that would promote automatic vars to static when possible later (e.g. after inlining) if it can prove it is safe to do so.
Wonder if SRA doesn't have the right infrastructure to optimize this. In any case, GCC 12 material.
Confirmed, there is another bug which is very similar to this one but filed years ago.
Dup. *** This bug has been marked as a duplicate of bug 59863 ***