Skip to content

[BUG] Cannot emit static constexpr function local variables #1093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bluetarpmedia opened this issue Jun 3, 2024 · 2 comments
Open

[BUG] Cannot emit static constexpr function local variables #1093

bluetarpmedia opened this issue Jun 3, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@bluetarpmedia
Copy link
Contributor

Describe the bug
I can't find a Cpp2 syntax to emit a static constexpr local variable. static constexpr variables are useful (particularly in debug/non-optimised builds) for look-up tables in a function where you want the data initialised once and also prefer to keep the variable close to its use in the function, rather than declaring it globally.

See:

To Reproduce
Run cppfront on this code:

main: () -> int = {
    ints: std::array == (11, 22, 33);
    it: == std::find(ints.cbegin(), ints.cend(), 33);
    return it*;
}

It lowers to:

auto main() -> int{
    std::array constexpr ints{ 11, 22, 33 };
    auto constexpr it = std::find(CPP2_UFCS(cbegin)(ints), CPP2_UFCS(cend)(ints), 33);
    return *cpp2::impl::assert_not_null(it); 
}

which produces a C++ compiler error:

main.cpp2:3:20: error: constexpr variable 'it' must be initialized by a constant expression
    3 |     auto constexpr it = std::find(CPP2_UFCS(cbegin)(ints), CPP2_UFCS(cend)(ints), 33);
      |                    ^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp2:3:20: note: pointer to subobject of 'ints' is not a constant expression
main.cpp2:2:26: note: address of non-static constexpr variable 'ints' may differ on each invocation of the enclosing function; add 'static' to give it a constant address
    2 |     std::array constexpr ints{ 11, 22, 33 };
      |                          ^
      |     static 

Repro on Godbolt

Why static constexpr

Here's a C++ example demonstrating why static constexpr is useful:

Side-by-side repro on Godbolt

With static constexpr

int main()
{
    static constexpr std::array ints = {11, 22, 33};
    constexpr auto it = std::find(ints.cbegin(), ints.cend(), 33);
    return *it;
}
MSVC Release `/O2`
main    PROC                                            ; COMDAT
        mov     eax, 33                             ; 00000021H
        ret     0
main    ENDP
MSVC Debug `/Od`
std::array<int,3> const `main'::`2'::ints DD 0bH      ; `main'::`2'::ints
        DD      016H
        DD      021H

it$ = 32
main    PROC
$LN3:
        sub     rsp, 56                             ; 00000038H
        lea     rax, OFFSET FLAT:std::array<int,3> const `main'::`2'::ints
        add     rax, 8
        mov     QWORD PTR it$[rsp], rax
        lea     rcx, QWORD PTR it$[rsp]
        call    int const & std::_Array_const_iterator<int,3>::operator*(void)const  ; std::_Array_const_iterator<int,3>::operator*
        mov     eax, DWORD PTR [rax]
        add     rsp, 56                             ; 00000038H
        ret     0
main    ENDP

Without static constexpr

int main()
{
    std::array ints = {11, 22, 33};
    auto it = std::find(ints.cbegin(), ints.cend(), 33);
    return *it;
}
MSVC Release `/O2`
ints$ = 32
__$ArrayPad$ = 48
main    PROC                                            ; COMDAT
$LN41:
        sub     rsp, 72                             ; 00000048H
        mov     rax, QWORD PTR __security_cookie
        xor     rax, rsp
        mov     QWORD PTR __$ArrayPad$[rsp], rax
        mov     r8d, 33                             ; 00000021H
        mov     DWORD PTR ints$[rsp], 11
        lea     rdx, QWORD PTR ints$[rsp+12]
        mov     DWORD PTR ints$[rsp+4], 22
        lea     rcx, QWORD PTR ints$[rsp]
        mov     DWORD PTR ints$[rsp+8], 33                ; 00000021H
        call    __std_find_trivial_4
        mov     eax, DWORD PTR [rax]
        mov     rcx, QWORD PTR __$ArrayPad$[rsp]
        xor     rcx, rsp
        call    __security_check_cookie
        add     rsp, 72                             ; 00000048H
        ret     0
main    ENDP
MSVC Debug `/Od`
voltbl  SEGMENT
        DDSymXIndex:    FLAT:main
voltbl  ENDS

$T1 = 32
$T2 = 40
$T3 = 48
it$ = 56
$T4 = 64
$T5 = 72
ints$ = 80
__$ArrayPad$ = 96
main    PROC
$LN3:
        sub     rsp, 120                      ; 00000078H
        mov     rax, QWORD PTR __security_cookie
        xor     rax, rsp
        mov     QWORD PTR __$ArrayPad$[rsp], rax
        mov     DWORD PTR ints$[rsp], 11
        mov     DWORD PTR ints$[rsp+4], 22
        mov     DWORD PTR ints$[rsp+8], 33                ; 00000021H
        mov     DWORD PTR $T1[rsp], 33                    ; 00000021H
        lea     rdx, QWORD PTR $T4[rsp]
        lea     rcx, QWORD PTR ints$[rsp]
        call    std::_Array_const_iterator<int,3> std::array<int,3>::cend(void)const  ; std::array<int,3>::cend
        mov     rax, QWORD PTR [rax]
        mov     QWORD PTR $T2[rsp], rax
        lea     rdx, QWORD PTR $T5[rsp]
        lea     rcx, QWORD PTR ints$[rsp]
        call    std::_Array_const_iterator<int,3> std::array<int,3>::cbegin(void)const  ; std::array<int,3>::cbegin
        mov     rax, QWORD PTR [rax]
        mov     QWORD PTR $T3[rsp], rax
        lea     r9, QWORD PTR $T1[rsp]
        mov     r8, QWORD PTR $T2[rsp]
        mov     rdx, QWORD PTR $T3[rsp]
        lea     rcx, QWORD PTR it$[rsp]
        call    std::_Array_const_iterator<int,3> std::find<std::_Array_const_iterator<int,3>,int>(std::_Array_const_iterator<int,3>,std::_Array_const_iterator<int,3>,int const &) ; std::find<std::_Array_const_iterator<int,3>,int>
        lea     rcx, QWORD PTR it$[rsp]
        call    int const & std::_Array_const_iterator<int,3>::operator*(void)const  ; std::_Array_const_iterator<int,3>::operator*
        mov     eax, DWORD PTR [rax]
        mov     rcx, QWORD PTR __$ArrayPad$[rsp]
        xor     rcx, rsp
        call    __security_check_cookie
        add     rsp, 120                      ; 00000078H
        ret     0
main    ENDP
@bluetarpmedia bluetarpmedia added the bug Something isn't working label Jun 3, 2024
@hsutter
Copy link
Owner

hsutter commented Jun 22, 2024

Thanks! More generally, Cpp2 doesn't yet support "magic statics" / static local variables, whether constexpr or not. I think your request is to support a "magic statics" equivalent.

I was dragging my feet on supporting that because call_once is still available for single-lazy-initialization semantics, so I was waiting to see if there was demand for the feature. However, call_once doesn't let you do the initialization of the constexpr value you want.

So it seems that a "static" or "once" or similar qualifier or similar is wanted, that lowers to magic statics...

@JohelEGP
Copy link
Contributor

JohelEGP commented Oct 4, 2024

See also #761 (comment).
Another reference from the above linked b589f5d#commitcomment-129028816:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants