-
Notifications
You must be signed in to change notification settings - Fork 90
Open
Description
Using clang
from trunk with -std=c++17 -Oz
, the following code uses overloaded
with an exhaustive set of lambdas to visit all cases of the variant
:
#include <https://raw.githubusercontent.com/mpark/variant/single-header/master/variant.hpp>
#include <functional>
#include <string>
#include <stdio.h>
namespace {
template <class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
};
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
}
enum class Foo { kValue };
enum class Bar { kValue };
using Callback = std::function<std::string(void)>;
using SumType = mpark::variant<Foo, Bar, Callback>;
void DoStuff(SumType s) {
mpark::visit(overloaded{
[](Foo f) { printf("Foo!\n");},
[](Bar b) { printf("Bar!\n");},
[](const Callback& c) { printf("Callback: %s\n", c().c_str()); },
},
s);
}
Even though the lambdas exhaustively handle all cases, MPark.Variant still generates error handling logic to throw bad_variant_access
exceptions (which as far as I can tell should never happen).
I think it'd be a nice optimization to drop the error handling entirely if the visitation is exhaustive.
Here's the current state of the optimized assembly in case this gets fixed:
DoStuff(mpark::variant<Foo, Bar, std::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > ()> >): # @DoStuff(mpark::variant<Foo, Bar, std::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > ()> >)
push r14
push rbx
sub rsp, 40
mov rbx, rdi
cmp byte ptr [rdi + 32], -1
lea rdi, [rsp + 7]
sete byte ptr [rdi]
push 1
pop rsi
call mpark::detail::any(std::initializer_list<bool>)
test al, al
jne .LBB0_8
movzx ecx, byte ptr [rbx + 32]
cmp rcx, 255
push -1
pop rax
cmovne rax, rcx
cmp rax, 2
je .LBB0_6
cmp rax, 1
je .LBB0_5
mov edi, offset .Lstr
jmp .LBB0_4
.LBB0_5:
mov edi, offset .Lstr.4
.LBB0_4:
call puts
jmp .LBB0_7
.LBB0_6:
lea r14, [rsp + 8]
mov rdi, r14
mov rsi, rbx
call std::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > ()>::operator()() const
mov rsi, qword ptr [r14]
mov edi, offset .L.str.3
xor eax, eax
call printf
mov rdi, r14
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [base object destructor]
.LBB0_7:
add rsp, 40
pop rbx
pop r14
ret
.LBB0_8:
call mpark::throw_bad_variant_access()
mpark::detail::any(std::initializer_list<bool>): # @mpark::detail::any(std::initializer_list<bool>)
xor eax, eax
.LBB1_1: # =>This Inner Loop Header: Depth=1
cmp rsi, rax
je .LBB1_4
cmp byte ptr [rdi + rax], 0
lea rax, [rax + 1]
je .LBB1_1
mov al, 1
ret
.LBB1_4:
xor eax, eax
ret
mpark::throw_bad_variant_access(): # @mpark::throw_bad_variant_access()
push rax
push 8
pop rdi
call __cxa_allocate_exception
mov qword ptr [rax], offset vtable for mpark::bad_variant_access+16
mov esi, offset typeinfo for mpark::bad_variant_access
mov edx, offset std::exception::~exception() [base object destructor]
mov rdi, rax
call __cxa_throw
mpark::bad_variant_access::~bad_variant_access() [deleting destructor]: # @mpark::bad_variant_access::~bad_variant_access() [deleting destructor]
push rbx
mov rbx, rdi
call std::exception::~exception() [base object destructor]
mov rdi, rbx
pop rbx
jmp operator delete(void*) # TAILCALL
mpark::bad_variant_access::what() const: # @mpark::bad_variant_access::what() const
mov eax, offset .L.str
ret
std::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > ()>::operator()() const: # @std::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > ()>::operator()() const
push rbx
cmp qword ptr [rsi + 16], 0
je .LBB5_2
mov rbx, rdi
call qword ptr [rsi + 24]
mov rax, rbx
pop rbx
ret
.LBB5_2:
call std::__throw_bad_function_call()
typeinfo name for mpark::bad_variant_access:
.asciz "N5mpark18bad_variant_accessE"
typeinfo for mpark::bad_variant_access:
.quad vtable for __cxxabiv1::__si_class_type_info+16
.quad typeinfo name for mpark::bad_variant_access
.quad typeinfo for std::exception
vtable for mpark::bad_variant_access:
.quad 0
.quad typeinfo for mpark::bad_variant_access
.quad std::exception::~exception() [base object destructor]
.quad mpark::bad_variant_access::~bad_variant_access() [deleting destructor]
.quad mpark::bad_variant_access::what() const
.L.str:
.asciz "bad_variant_access"
.L.str.3:
.asciz "Callback: %s\n"
.Lstr:
.asciz "Foo!"
.Lstr.4:
.asciz "Bar!"
Metadata
Metadata
Assignees
Labels
No labels