https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95384
Bug ID: 95384 Summary: Poor codegen cause by using base class instead of member for Optional construction Product: gcc Version: 10.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: --- Following up on #95383: struct nullopt_t {} inline constexpr nullopt{}; template <typename T> struct OptionalStorage { struct Empty { }; union { Empty _; T value; }; bool engaged; OptionalStorage(nullopt_t) : _(), engaged(false) { } OptionalStorage(T v) : value(v), engaged(true) { } }; template <typename T> struct OptionalWithBase : OptionalStorage<T> { using OptionalStorage<T>::OptionalStorage; }; template <typename T> struct OptionalWithMember { OptionalStorage<T> o; OptionalWithMember(nullopt_t) : o(nullopt) { } OptionalWithMember(T v) : o(v) { } }; OptionalWithBase<int> foo_with_base(bool b) { if (b) { return 42; } return nullopt; } OptionalWithMember<int> foo_with_member(bool b) { if (b) { return 42; } return nullopt; } OptionalWithBase<T> and OptionalWithMember<T> should be the same thing. It's just that one inherits from its storage and the other has it as a member. But the codegen is very different (https://godbolt.org/z/j8m68Y), probably something to do with tail padding? gcc 10.1 -O2: foo_with_base(bool): test dil, dil je .L2 mov DWORD PTR [rsp-8], 42 mov BYTE PTR [rsp-4], 1 mov rax, QWORD PTR [rsp-8] ret .L2: mov BYTE PTR [rsp-4], 0 mov rax, QWORD PTR [rsp-8] ret foo_with_member(bool): test dil, dil mov eax, 0 movabs rdx, 4294967338 cmovne rax, rdx ret gcc 10.2 -O3 or gcc trunk -O2: foo_with_base(bool): xor eax, eax test dil, dil je .L2 mov DWORD PTR [rsp-8], 42 mov eax, 1 .L2: mov BYTE PTR [rsp-4], al mov rax, QWORD PTR [rsp-8] ret foo_with_member(bool): xor edx, edx mov ecx, 42 test dil, dil cmovne rax, rcx mov ecx, 1 cmovne rdx, rcx movabs rcx, -1095216660481 and rax, rcx sal rdx, 32 or rax, rdx ret clang 10, -O2 or -O3: foo_with_base(bool): # @foo_with_base(bool) shl rdi, 32 lea rax, [rdi + 42] ret foo_with_member(bool): # @foo_with_member(bool) shl rdi, 32 lea rax, [rdi + 42] ret