https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114589
Bug ID: 114589 Summary: missed optimization: losing bool range information Product: gcc Version: 13.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: barry.revzin at gmail dot com Target Milestone: --- Consider the following example: template <class T> struct simple_optional { bool has_val; T val; auto begin() const -> T const* { return &val; } #ifdef SIMPLE auto end() const -> T const* { return &val + (has_val ? 1 : 0); } #else auto end() const -> T const* { return has_val ? &val + 1 : &val; } #endif }; void f(int); void call_f(simple_optional<int> const& o) { for (int i : o) { f(i); } } This function should call f at most one time. With the SIMPLE implementation that adds (has_val ? 1 : 0), or simply has_val, or static_cast<int>(has_val), or any version thereof - gcc trunk -O3 still emits a loop: call_f(simple_optional<int> const&): push rbp push rbx lea rbx, [rdi+4] sub rsp, 8 movzx edx, BYTE PTR [rdi] lea rbp, [rbx+rdx*4] test dl, dl je .L1 .L3: mov edi, DWORD PTR [rbx] add rbx, 4 call f(int) cmp rbp, rbx jne .L3 .L1: add rsp, 8 pop rbx pop rbp ret With the other approach, where end() explicitly returns either &val + 1 or &val, gcc does not emit a loop: call_f(simple_optional<int> const&): cmp BYTE PTR [rdi], 0 jne .L4 ret .L4: mov edi, DWORD PTR [rdi+4] jmp f(int) On compiler explorer: https://godbolt.org/z/jaMxqsj5q