Overhaul function calls and usage

- add noexcept to some of the core function calls
- type usage for both trampolines and yields can now be fully tracked, at the expense of more template instantiations when using both
- exceptions should be less prone to explosion in C versions, but will break in C++ code (the trampolines need to be modified for usertype calls to avoid this problem, specifically)
This commit is contained in:
ThePhD 2020-12-17 23:25:48 -05:00
parent 561c90abf4
commit d39330eab9
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
20 changed files with 923 additions and 628 deletions

View File

@ -63,7 +63,7 @@ functions and argument passing
All arguments are forwarded. Unlike :doc:`get/set/operator[] on sol::state<api/state>` or :doc:`sol::table<api/table>`, value semantics are not used here. It is forwarding reference semantics, which do not copy/move unless it is specifically done by the receiving functions / specifically done by the user.
You can change this behavior by defining ``SOL_FUNCTION_CALL_VALUE_SEMANTICS``, as defined in the :doc:`safety configuration page<safety>`.
You can change this behavior by defining ``SOL_FUNCTION_CALL_VALUE_SEMANTICS``, as defined in the :doc:`safety configuration page<safety>`. You can also change it for specific types using the ``sol::is_value_semantic_for_function<T>`` template and _partially specializing_ it to make either ``std::true_type``, ``std::false_type``, or equivalent ``true``/``false`` functionality.
.. note::

View File

@ -31,39 +31,40 @@ namespace sol { namespace detail {
template <typename T, std::size_t tag = 0, typename = void>
struct ebco {
T value_;
T m_value;
ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco(const T& v) : value_(v) {};
ebco(T&& v) : value_(std::move(v)) {};
ebco& operator=(const T& v) {
value_ = v;
ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : m_value(v) {};
ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : m_value(std::move(v)) {};
ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) {
m_value = v;
return *this;
}
ebco& operator=(T&& v) {
value_ = std::move(v);
ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) {
m_value = std::move(v);
return *this;
};
template <typename Arg, typename... Args,
typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>>
ebco(Arg&& arg, Args&&... args) : value_(std::forward<Arg>(arg), std::forward<Args>(args)...) {
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>>
ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>)
: m_value(std::forward<Arg>(arg), std::forward<Args>(args)...) {
}
T& value() & {
return value_;
T& value() & noexcept {
return m_value;
}
T const& value() const& {
return value_;
T const& value() const& noexcept {
return m_value;
}
T&& value() && {
return std::move(value_);
T&& value() && noexcept {
return std::move(m_value);
}
};
@ -72,56 +73,58 @@ namespace sol { namespace detail {
ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco(const T& v) : T(v) {};
ebco(T&& v) : T(std::move(v)) {};
ebco(const T& v) noexcept(std::is_nothrow_copy_constructible_v<T>) : T(v) {};
ebco(T&& v) noexcept(std::is_nothrow_move_constructible_v<T>) : T(std::move(v)) {};
template <typename Arg, typename... Args,
typename = std::enable_if_t<!std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>,
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T>>>
ebco(Arg&& arg, Args&&... args) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) {
ebco> && !std::is_same_v<std::remove_reference_t<std::remove_cv_t<Arg>>, T> && (sizeof...(Args) > 0 || !std::is_convertible_v<Arg, T>)>>
ebco(Arg&& arg, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Arg, Args...>) : T(std::forward<Arg>(arg), std::forward<Args>(args)...) {
}
ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(const T& v) {
ebco& operator=(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) {
static_cast<T&>(*this) = v;
return *this;
}
ebco& operator=(T&& v) {
ebco& operator=(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) {
static_cast<T&>(*this) = std::move(v);
return *this;
};
T& value() & {
T& value() & noexcept {
return static_cast<T&>(*this);
}
T const& value() const& {
T const& value() const& noexcept {
return static_cast<T const&>(*this);
}
T&& value() && {
T&& value() && noexcept {
return std::move(static_cast<T&>(*this));
}
};
template <typename T, std::size_t tag>
struct ebco<T&, tag> {
T& ref;
private:
T* m_ref;
public:
ebco() = default;
ebco(const ebco&) = default;
ebco(ebco&&) = default;
ebco(T& v) : ref(v) {};
ebco(T& v) noexcept : m_ref(std::addressof(v)) {};
ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(T& v) {
ref = v;
ebco& operator=(T& v) noexcept {
m_ref = std::addressof(v);
return *this;
}
T& value() const {
return const_cast<ebco<T&, tag>&>(*this).ref;
T& value() const noexcept {
return *(const_cast<ebco<T&, tag>&>(*this).m_ref);
}
};
@ -130,26 +133,22 @@ namespace sol { namespace detail {
T&& ref;
ebco() = default;
ebco(const ebco&) = default;
ebco(const ebco&) = delete;
ebco(ebco&&) = default;
ebco(T&& v) : ref(v) {};
ebco(T&& v) noexcept : ref(v) {};
ebco& operator=(const ebco&) = default;
ebco& operator=(ebco&&) = default;
ebco& operator=(T&& v) {
ref = std::move(v);
return *this;
}
ebco& operator=(const ebco&) = delete;
ebco& operator=(ebco&&) = delete;
T& value() & {
T& value() & noexcept {
return ref;
}
const T& value() const& {
const T& value() const& noexcept {
return ref;
}
T&& value() && {
T&& value() && noexcept {
return std::move(ref);
}
};

View File

@ -67,7 +67,7 @@ namespace sol {
struct c_function_invocation { };
template <bool is_yielding, typename Fx, typename... Args>
template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args>
void select(lua_State* L, Fx&& fx, Args&&... args);
template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args>
@ -81,33 +81,33 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args>
template <bool is_yielding, bool no_trampoline, typename R, typename... A, typename Fx, typename... Args>
void select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
using dFx = std::decay_t<meta::unwrap_unqualified_t<Fx>>;
using fx_ptr_t = R (*)(A...);
constexpr bool is_convertible = std::is_convertible_v<dFx, fx_ptr_t>;
if constexpr (is_convertible) {
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
select<is_yielding>(L, std::move(fxptr), std::forward<Args>(args)...);
select<is_yielding, no_trampoline>(L, std::move(fxptr), std::forward<Args>(args)...);
}
else {
using F = function_detail::functor_function<dFx, false, true>;
select_set_fx<is_yielding, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
template <bool is_yielding, typename Fx, typename... Args>
template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args>
void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
select_convertible<is_yielding, no_trampoline>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename... Args>
template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args>
void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) {
using uFx = meta::unqualified_t<Fx>;
if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<uFx>::object_type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::template call<is_yielding, no_trampoline>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
@ -118,7 +118,8 @@ namespace sol {
using Tu = typename meta::meta_detail::unqualified_non_alias<Args...>::type;
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call;
lua_CFunction freefunc
= &function_detail::upvalue_this_member_variable<typename Tu::type, Fx>::template call<is_yielding, no_trampoline>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
@ -129,8 +130,8 @@ namespace sol {
typedef std::decay_t<Fx> dFx;
dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<Args>(args)...);
lua_CFunction freefunc
= &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>,
meta::unqualified_t<Fx>>::template call<is_yielding, no_trampoline>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
@ -140,26 +141,26 @@ namespace sol {
}
else {
using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;
using F = function_detail::member_variable<Tu, clean_fx, is_yielding>;
select_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
using F = function_detail::member_variable<Tu, clean_fx, is_yielding, no_trampoline>;
select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
else {
using C = typename meta::bind_traits<uFx>::object_type;
using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;
using F = function_detail::member_variable<C, clean_fx, is_yielding>;
select_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
using F = function_detail::member_variable<C, clean_fx, is_yielding, no_trampoline>;
select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
template <bool is_yielding, bool no_trampoline, typename Fx, typename T, typename... Args>
void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
using dFx = std::decay_t<Fx>;
using Tu = meta::unqualified_t<T>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
(void)obj;
using C = typename Tu::type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx>::template call<is_yielding, no_trampoline>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
@ -170,7 +171,8 @@ namespace sol {
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (is_reference) {
auto userptr = detail::ptr(std::forward<T>(obj));
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx, is_yielding>::call;
lua_CFunction freefunc
= &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx>::template call<is_yielding, no_trampoline>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
@ -179,18 +181,18 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues));
}
else {
using F = function_detail::member_function<Tu, dFx, is_yielding>;
select_set_fx<false, false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
using F = function_detail::member_function<Tu, dFx, is_yielding, no_trampoline>;
select_set_fx<is_yielding, no_trampoline, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
}
}
template <bool is_yielding, typename Fx, typename... Args>
template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args>
void select_member_function(lua_State* L, Fx&& fx, Args&&... args) {
using dFx = std::decay_t<Fx>;
if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx>::template call<is_yielding, no_trampoline>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
@ -198,11 +200,11 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues));
}
else {
select_member_function_with<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
select_member_function_with<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
template <bool is_yielding, typename Fx, typename... Args>
template <bool is_yielding, bool no_trampoline, typename Fx, typename... Args>
void select(lua_State* L, Fx&& fx, Args&&... args) {
using uFx = meta::unqualified_t<Fx>;
if constexpr (is_lua_reference_v<uFx>) {
@ -210,26 +212,49 @@ namespace sol {
stack::push(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
else if constexpr (is_lua_c_function_v<uFx>) {
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push(L, std::forward<Fx>(fx));
if constexpr (no_trampoline) {
if (is_yielding) {
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push(L, std::forward<Fx>(fx));
#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)
if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) {
detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>;
lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), 2);
if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) {
detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<true>;
lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), upvalues);
}
else
#endif
{
lua_CFunction cf = &function_detail::lua_c_wrapper<true>;
lua_pushcclosure(L, cf, upvalues);
}
}
else {
lua_pushcclosure(L, std::forward<Fx>(fx), 0);
}
}
else {
lua_CFunction cf = &lua_c_wrapper<is_yielding>;
lua_pushcclosure(L, cf, 2);
}
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push(L, std::forward<Fx>(fx));
#if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)
if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) {
detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>;
lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), upvalues);
}
else {
lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>;
lua_pushcclosure(L, cf, upvalues);
}
#else
lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>;
lua_pushcclosure(L, cf, 2);
lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>;
lua_pushcclosure(L, cf, upvalues);
#endif
}
}
else if constexpr (std::is_function_v<std::remove_pointer_t<uFx>>) {
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call;
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::template call<is_yielding, no_trampoline>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
@ -237,13 +262,13 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues));
}
else if constexpr (std::is_member_function_pointer_v<uFx>) {
select_member_function<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
select_member_function<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
else if constexpr (meta::is_member_object_v<uFx>) {
select_member_variable<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
select_member_variable<is_yielding, no_trampoline>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
else {
select_convertible<is_yielding>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
select_convertible<is_yielding, no_trampoline>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
} // namespace function_detail
@ -262,7 +287,7 @@ namespace sol {
}
}
else {
function_detail::select<is_yielding>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);
function_detail::select<is_yielding, true>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);
return 1;
}
}
@ -290,7 +315,7 @@ namespace sol {
return stack::push<T>(L, detail::yield_tag, f.func, std::forward<Args>(args)...);
}
else {
function_detail::select<true>(L, f.func, std::forward<Args>(args)...);
function_detail::select<true, true>(L, f.func, std::forward<Args>(args)...);
return 1;
}
}
@ -301,7 +326,7 @@ namespace sol {
return stack::push<T>(L, detail::yield_tag, std::move(f.func), std::forward<Args>(args)...);
}
else {
function_detail::select<true>(L, std::move(f.func), std::forward<Args>(args)...);
function_detail::select<true, true>(L, std::move(f.func), std::forward<Args>(args)...);
return 1;
}
}
@ -327,7 +352,7 @@ namespace sol {
struct unqualified_pusher<std::function<Signature>> {
static int push(lua_State* L, detail::yield_tag_t, const std::function<Signature>& fx) {
if (fx) {
function_detail::select<true>(L, fx);
function_detail::select<true, true>(L, fx);
return 1;
}
return stack::push(L, lua_nil);
@ -335,7 +360,7 @@ namespace sol {
static int push(lua_State* L, detail::yield_tag_t, std::function<Signature>&& fx) {
if (fx) {
function_detail::select<true>(L, std::move(fx));
function_detail::select<true, true>(L, std::move(fx));
return 1;
}
return stack::push(L, lua_nil);
@ -343,7 +368,7 @@ namespace sol {
static int push(lua_State* L, const std::function<Signature>& fx) {
if (fx) {
function_detail::select<false>(L, fx);
function_detail::select<false, true>(L, fx);
return 1;
}
return stack::push(L, lua_nil);
@ -351,7 +376,7 @@ namespace sol {
static int push(lua_State* L, std::function<Signature>&& fx) {
if (fx) {
function_detail::select<false>(L, std::move(fx));
function_detail::select<false, true>(L, std::move(fx));
return 1;
}
return stack::push(L, lua_nil);
@ -362,7 +387,7 @@ namespace sol {
struct unqualified_pusher<Signature, std::enable_if_t<meta::is_member_object_or_function_v<Signature>>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
function_detail::select<false>(L, std::forward<Args>(args)...);
function_detail::select<false, true>(L, std::forward<Args>(args)...);
return 1;
}
};
@ -379,7 +404,7 @@ namespace sol {
>::value>> {
template <typename F>
static int push(lua_State* L, F&& f) {
function_detail::select<false>(L, std::forward<F>(f));
function_detail::select<false, true>(L, std::forward<F>(f));
return 1;
}
};

View File

@ -31,14 +31,15 @@ namespace sol { namespace function_detail {
template <typename Func, bool is_yielding, bool no_trampoline>
struct functor_function {
typedef std::decay_t<meta::unwrap_unqualified_t<Func>> function_type;
function_type fx;
function_type invocation;
template <typename... Args>
functor_function(function_type f, Args&&... args) : fx(std::move(f), std::forward<Args>(args)...) {
functor_function(function_type f, Args&&... args) noexcept(std::is_nothrow_constructible_v<function_type, function_type, Args...>)
: invocation(std::move(f), std::forward<Args>(args)...) {
}
int call(lua_State* L) {
int nr = call_detail::call_wrapped<void, true, false>(L, fx);
static int call(lua_State* L, functor_function& self) noexcept(noexcept(call_detail::call_wrapped<void, true, false>(L, self.invocation))) {
int nr = call_detail::call_wrapped<void, true, false>(L, self.invocation);
if (is_yielding) {
return lua_yield(L, nr);
}
@ -47,31 +48,39 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
if (!no_trampoline) {
auto f = [&](lua_State*) -> int { return this->call(L); };
return detail::trampoline(L, f);
int operator()(lua_State* L) noexcept(noexcept(call_detail::call_wrapped<void, true, false>(L, invocation))) {
if constexpr (no_trampoline) {
return call(L, *this);
}
else {
return call(L);
return detail::trampoline(L, &call, *this);
}
}
};
template <typename T, typename Function, bool is_yielding>
template <typename T, typename Function, bool is_yielding, bool no_trampoline>
struct member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_lists;
using traits_type = meta::bind_traits<function_type>;
function_type invocation;
T member;
template <typename... Args>
member_function(function_type f, Args&&... args) : invocation(std::move(f)), member(std::forward<Args>(args)...) {
member_function(function_type f, Args&&... args) noexcept(
std::is_nothrow_constructible_v<function_type, function_type>&& std::is_nothrow_constructible_v<T, Args...>)
: invocation(std::move(f)), member(std::forward<Args>(args)...) {
}
int call(lua_State* L) {
int nr = call_detail::call_wrapped<T, true, false, -1>(L, invocation, detail::unwrap(detail::deref(member)));
static int call(lua_State* L, member_function& self)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
#else
noexcept(traits_type::is_noexcept)
#endif
{
int nr = call_detail::call_wrapped<T, true, false, -1>(L, self.invocation, detail::unwrap(detail::deref(self.member)));
if (is_yielding) {
return lua_yield(L, nr);
}
@ -80,13 +89,23 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
auto f = [&](lua_State*) -> int { return this->call(L); };
return detail::trampoline(L, f);
int operator()(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
#else
noexcept(traits_type::is_noexcept)
#endif
{
if constexpr (no_trampoline) {
return call(L, *this);
}
else {
return detail::trampoline(L, &call, *this);
}
}
};
template <typename T, typename Function, bool is_yielding>
template <typename T, typename Function, bool is_yielding, bool no_trampoline>
struct member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef typename meta::bind_traits<function_type>::return_type return_type;
@ -96,19 +115,21 @@ namespace sol { namespace function_detail {
typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M;
template <typename... Args>
member_variable(function_type v, Args&&... args) : var(std::move(v)), member(std::forward<Args>(args)...) {
member_variable(function_type v, Args&&... args) noexcept(
std::is_nothrow_constructible_v<function_type, function_type>&& std::is_nothrow_constructible_v<T, Args...>)
: var(std::move(v)), member(std::forward<Args>(args)...) {
}
int call(lua_State* L) {
static int call(lua_State* L, member_variable& self) noexcept(std::is_nothrow_copy_assignable_v<T>) {
int nr;
{
M mem = detail::unwrap(detail::deref(member));
M mem = detail::unwrap(detail::deref(self.member));
switch (lua_gettop(L)) {
case 0:
nr = call_detail::call_wrapped<T, true, false, -1>(L, var, mem);
nr = call_detail::call_wrapped<T, true, false, -1>(L, self.var, mem);
break;
case 1:
nr = call_detail::call_wrapped<T, false, false, -1>(L, var, mem);
nr = call_detail::call_wrapped<T, false, false, -1>(L, self.var, mem);
break;
default:
nr = luaL_error(L, "sol: incorrect number of arguments to member variable function");
@ -123,9 +144,13 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
auto f = [&](lua_State*) -> int { return this->call(L); };
return detail::trampoline(L, f);
int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
if constexpr (no_trampoline) {
return call(L, *this);
}
else {
return detail::trampoline(L, &call, *this);
}
}
};
}} // namespace sol::function_detail

View File

@ -29,7 +29,7 @@
#include <sol/bind_traits.hpp>
namespace sol { namespace function_detail {
template <typename Function, bool is_yielding>
template <typename Function>
struct upvalue_free_function {
using function_type = std::remove_pointer_t<std::decay_t<Function>>;
using traits_type = meta::bind_traits<function_type>;
@ -46,8 +46,15 @@ namespace sol { namespace function_detail {
return call_detail::call_wrapped<void, true, false>(L, fx);
}
template <bool is_yielding, bool no_trampoline>
static int call(lua_State* L) {
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);
}
else {
nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
}
if (is_yielding) {
return lua_yield(L, nr);
}
@ -61,7 +68,7 @@ namespace sol { namespace function_detail {
}
};
template <typename T, typename Function, bool is_yielding>
template <typename T, typename Function>
struct upvalue_member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type;
@ -83,6 +90,7 @@ namespace sol { namespace function_detail {
return call_detail::call_wrapped<T, true, false, -1>(L, memfx, item);
}
template <bool is_yielding, bool no_trampoline>
static int call(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
@ -90,7 +98,13 @@ namespace sol { namespace function_detail {
noexcept(traits_type::is_noexcept)
#endif
{
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);
}
else {
nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
}
if (is_yielding) {
return lua_yield(L, nr);
}
@ -99,12 +113,18 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
int operator()(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
#else
noexcept(traits_type::is_noexcept)
#endif
{
return call(L);
}
};
template <typename T, typename Function, bool is_yielding>
template <typename T, typename Function>
struct upvalue_member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type;
@ -135,6 +155,7 @@ namespace sol { namespace function_detail {
}
}
template <bool is_yielding, bool no_trampoline>
static int call(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
@ -142,7 +163,13 @@ namespace sol { namespace function_detail {
noexcept(traits_type::is_noexcept)
#endif
{
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);
}
else {
nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
}
if (is_yielding) {
return lua_yield(L, nr);
}
@ -151,13 +178,19 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
int operator()(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
#else
noexcept(traits_type::is_noexcept)
#endif
{
return call(L);
}
};
template <typename T, typename Function, bool is_yielding>
struct upvalue_member_variable<T, readonly_wrapper<Function>, is_yielding> {
template <typename T, typename Function>
struct upvalue_member_variable<T, readonly_wrapper<Function>> {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type;
@ -185,6 +218,7 @@ namespace sol { namespace function_detail {
}
}
template <bool is_yielding, bool no_trampoline>
static int call(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
@ -192,7 +226,13 @@ namespace sol { namespace function_detail {
noexcept(traits_type::is_noexcept)
#endif
{
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);
}
else {
nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
}
if (is_yielding) {
return lua_yield(L, nr);
}
@ -201,12 +241,18 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
int operator()(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
#else
noexcept(traits_type::is_noexcept)
#endif
{
return call(L);
}
};
template <typename T, typename Function, bool is_yielding>
template <typename T, typename Function>
struct upvalue_this_member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type;
@ -224,6 +270,7 @@ namespace sol { namespace function_detail {
return call_detail::call_wrapped<T, false, false>(L, memfx);
}
template <bool is_yielding, bool no_trampoline>
static int call(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
@ -231,7 +278,13 @@ namespace sol { namespace function_detail {
noexcept(traits_type::is_noexcept)
#endif
{
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);
}
else {
nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
}
if (is_yielding) {
return lua_yield(L, nr);
}
@ -240,16 +293,22 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
int operator()(lua_State* L)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_)
// MSVC is broken, what a surprise...
#else
noexcept(traits_type::is_noexcept)
#endif
{
return call(L);
}
};
template <typename T, typename Function, bool is_yielding>
template <typename T, typename Function>
struct upvalue_this_member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
static int real_call(lua_State* L) noexcept(false) {
static int real_call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
// Layout:
// idx 1...n: verbatim data of member variable pointer
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);
@ -264,8 +323,15 @@ namespace sol { namespace function_detail {
}
}
static int call(lua_State* L) {
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
template <bool is_yielding, bool no_trampoline>
static int call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);
}
else {
nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
}
if (is_yielding) {
return lua_yield(L, nr);
}
@ -274,17 +340,17 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
return call(L);
}
};
template <typename T, typename Function, bool is_yielding>
struct upvalue_this_member_variable<T, readonly_wrapper<Function>, is_yielding> {
template <typename T, typename Function>
struct upvalue_this_member_variable<T, readonly_wrapper<Function>> {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type;
static int real_call(lua_State* L) noexcept(false) {
static int real_call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
// Layout:
// idx 1...n: verbatim data of member variable pointer
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);
@ -297,8 +363,15 @@ namespace sol { namespace function_detail {
}
}
static int call(lua_State* L) {
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
template <bool is_yielding, bool no_trampoline>
static int call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);
}
else {
nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
}
if (is_yielding) {
return lua_yield(L, nr);
}
@ -307,7 +380,7 @@ namespace sol { namespace function_detail {
}
}
int operator()(lua_State* L) {
int operator()(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
return call(L);
}
};

View File

@ -133,7 +133,7 @@ namespace sol {
struct wrap {
typedef F type;
static int call(lua_State* L) {
static int call(lua_State* L) noexcept(noexcept(c_call<type, f>(L))) {
return c_call<type, f>(L);
}
};

View File

@ -415,34 +415,55 @@ namespace sol { namespace stack {
template <typename T>
struct unqualified_pusher<as_table_t<T>> {
static int push(lua_State* L, const T& v) {
static int push(lua_State* L, const as_table_t<T>& value_) {
using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>;
if constexpr (is_container_v<inner_t>) {
return stack::push<detail::as_table_tag<T>>(L, v);
return stack::push<detail::as_table_tag<T>>(L, value_.value());
}
else {
return stack::push(L, v);
return stack::push(L, value_.value());
}
}
static int push(lua_State* L, const T& value_) {
using inner_t = std::remove_pointer_t<meta::unwrap_unqualified_t<T>>;
if constexpr (is_container_v<inner_t>) {
return stack::push<detail::as_table_tag<T>>(L, value_);
}
else {
return stack::push(L, value_);
}
}
};
template <typename T>
struct unqualified_pusher<nested<T>> {
static int push(lua_State* L, const T& tablecont) {
static int push(lua_State* L, const T& nested_value) noexcept {
using Tu = meta::unwrap_unqualified_t<T>;
using inner_t = std::remove_pointer_t<Tu>;
if constexpr (is_container_v<inner_t>) {
return stack::push<detail::as_table_tag<T>>(L, tablecont, nested_tag);
return stack::push<detail::as_table_tag<T>>(L, nested_value, nested_tag);
}
else {
return stack::push<Tu>(L, tablecont);
return stack::push<Tu>(L, nested_value);
}
}
static int push(lua_State* L, const nested<T>& nested_wrapper_) noexcept {
using Tu = meta::unwrap_unqualified_t<T>;
using inner_t = std::remove_pointer_t<Tu>;
if constexpr (is_container_v<inner_t>) {
return stack::push<detail::as_table_tag<T>>(L, nested_wrapper_.value(), nested_tag);
}
else {
return stack::push<Tu>(L, nested_wrapper_.value());
}
}
};
template <typename T>
struct unqualified_pusher<std::initializer_list<T>> {
static int push(lua_State* L, const std::initializer_list<T>& il) {
static int push(lua_State* L, const std::initializer_list<T>& il) noexcept {
unqualified_pusher<detail::as_table_tag<std::initializer_list<T>>> p {};
// silence annoying VC++ warning
(void)p;
@ -452,7 +473,7 @@ namespace sol { namespace stack {
template <>
struct unqualified_pusher<lua_nil_t> {
static int push(lua_State* L, lua_nil_t) {
static int push(lua_State* L, lua_nil_t) noexcept {
#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow
@ -463,7 +484,7 @@ namespace sol { namespace stack {
template <>
struct unqualified_pusher<stack_count> {
static int push(lua_State*, stack_count st) {
static int push(lua_State*, stack_count st) noexcept {
return st.count;
}
};
@ -481,7 +502,7 @@ namespace sol { namespace stack {
template <>
struct unqualified_pusher<std::remove_pointer_t<lua_CFunction>> {
static int push(lua_State* L, lua_CFunction func, int n = 0) {
static int push(lua_State* L, lua_CFunction func, int n = 0) noexcept {
#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow
@ -553,7 +574,7 @@ namespace sol { namespace stack {
template <>
struct unqualified_pusher<void*> {
static int push(lua_State* L, void* userdata) {
static int push(lua_State* L, void* userdata) noexcept {
#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow
@ -564,7 +585,7 @@ namespace sol { namespace stack {
template <>
struct unqualified_pusher<const void*> {
static int push(lua_State* L, const void* userdata) {
static int push(lua_State* L, const void* userdata) noexcept {
#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow
@ -575,7 +596,7 @@ namespace sol { namespace stack {
template <>
struct unqualified_pusher<lightuserdata_value> {
static int push(lua_State* L, lightuserdata_value userdata) {
static int push(lua_State* L, lightuserdata_value userdata) noexcept {
#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow
@ -586,7 +607,7 @@ namespace sol { namespace stack {
template <typename T>
struct unqualified_pusher<light<T>> {
static int push(lua_State* L, light<T> l) {
static int push(lua_State* L, light<T> l) noexcept {
#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
luaL_checkstack(L, 1, detail::not_enough_stack_space_generic);
#endif // make sure stack doesn't overflow
@ -645,17 +666,17 @@ namespace sol { namespace stack {
static int push(lua_State* L, user<T>&& u) {
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
return push_with(L, name, std::move(u.value));
return push_with(L, name, std::move(u.value()));
}
static int push(lua_State* L, no_metatable_t, const user<T>& u) {
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
return push_with<false>(L, name, u.value);
return push_with<false>(L, name, u.value());
}
static int push(lua_State* L, no_metatable_t, user<T>&& u) {
const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0];
return push_with<false>(L, name, std::move(u.value));
return push_with<false>(L, name, std::move(u.value()));
}
};
@ -666,7 +687,7 @@ namespace sol { namespace stack {
luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata);
#endif // make sure stack doesn't overflow
void** ud = detail::usertype_allocate_pointer<void>(L);
*ud = data.value;
*ud = data.value();
return 1;
}
};
@ -1137,30 +1158,41 @@ namespace sol { namespace stack {
}
};
template <typename T>
struct unqualified_pusher<forward_as_value_t<T>> {
static int push(lua_State* L, const forward_as_value_t<T>& value_) {
return stack::push<T>(L, value_.value());
}
static int push(lua_State* L, forward_as_value_t<T>&& value_) {
return stack::push<T>(L, std::move(value_).value());
}
};
template <>
struct unqualified_pusher<nullopt_t> {
static int push(lua_State* L, nullopt_t) {
static int push(lua_State* L, nullopt_t) noexcept {
return stack::push(L, lua_nil);
}
};
template <>
struct unqualified_pusher<std::nullptr_t> {
static int push(lua_State* L, std::nullptr_t) {
static int push(lua_State* L, std::nullptr_t) noexcept {
return stack::push(L, lua_nil);
}
};
template <>
struct unqualified_pusher<this_state> {
static int push(lua_State*, const this_state&) {
static int push(lua_State*, const this_state&) noexcept {
return 0;
}
};
template <>
struct unqualified_pusher<this_main_state> {
static int push(lua_State*, const this_main_state&) {
static int push(lua_State*, const this_main_state&) noexcept {
return 0;
}
};
@ -1198,7 +1230,7 @@ namespace sol { namespace stack {
struct push_function {
lua_State* L;
push_function(lua_State* L) : L(L) {
push_function(lua_State* L) noexcept : L(L) {
}
template <typename T>

View File

@ -115,7 +115,7 @@ namespace sol {
template <typename T>
table_proxy&& operator=(T&& other) && {
using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu> && !detail::is_msvc_callable_rigged_v<T>) {
return std::move(*this).set_function(std::forward<T>(other));
}
else {

View File

@ -189,29 +189,49 @@ namespace sol {
};
struct userdata_value {
void* value;
userdata_value(void* data) : value(data) {
private:
void* m_value;
public:
userdata_value(void* data) : m_value(data) {
}
void* value() const {
return m_value;
}
operator void*() const {
return value;
return value();
}
};
template <typename L>
template <typename T>
struct light {
L* value;
private:
static_assert(!std::is_void_v<T>, "the type for light will never be void");
T* m_value;
light(L& x) : value(std::addressof(x)) {
public:
light(T& x) : m_value(std::addressof(x)) {
}
light(L* x) : value(x) {
light(T* x) : m_value(x) {
}
light(void* x) : value(static_cast<L*>(x)) {
explicit light(void* x) : m_value(static_cast<T*>(x)) {
}
operator L*() const {
return value;
T* value() const {
return m_value;
}
operator L&() const {
return *value;
operator T*() const {
return m_value;
}
operator T&() const {
return *m_value;
}
void* void_value() const {
return m_value;
}
};
@ -221,20 +241,30 @@ namespace sol {
return light<L>(l);
}
template <typename U>
struct user {
U value;
template <typename T>
struct user : private detail::ebco<T> {
private:
using base_t = detail::ebco<T>;
user(U&& x) : value(std::forward<U>(x)) {
public:
using base_t::base_t;
using base_t::value;
operator std::add_pointer_t<std::remove_reference_t<T>>() {
return std::addressof(this->base_t::value());
}
operator std::add_pointer_t<std::remove_reference_t<U>>() {
return std::addressof(value);
operator std::add_pointer_t<std::add_const_t<std::remove_reference_t<T>>>() const {
return std::addressof(this->base_t::value());
}
operator std::add_lvalue_reference_t<U>() {
return value;
operator std::add_lvalue_reference_t<T>() {
return this->base_t::value();
}
operator std::add_const_t<std::add_lvalue_reference_t<U>>&() const {
return value;
operator std::add_const_t<std::add_lvalue_reference_t<T>>&() const {
return this->base_t::value();
}
};
@ -245,11 +275,14 @@ namespace sol {
}
template <typename T>
struct metatable_registry_key {
T key;
struct metatable_registry_key : private detail::ebco<T> {
private:
using base_t = detail::ebco<T>;
metatable_registry_key(T key) : key(std::forward<T>(key)) {
}
public:
using base_t::base_t;
using base_t::value;
};
template <typename T>
@ -300,9 +333,9 @@ namespace sol {
}
template <typename T>
struct as_table_t {
struct as_table_t : private detail::ebco<T> {
private:
T value_;
using base_t = detail::ebco<T>;
public:
as_table_t() = default;
@ -310,36 +343,24 @@ namespace sol {
as_table_t(as_table_t&&) = default;
as_table_t& operator=(const as_table_t&) = default;
as_table_t& operator=(as_table_t&&) = default;
template <typename Arg,
meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_table_t>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
as_table_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {
}
template <typename Arg0, typename Arg1, typename... Args>
as_table_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
}
T& value() & {
return value_;
}
using base_t::base_t;
T&& value() && {
return std::move(value_);
}
const T& value() const& {
return value_;
}
using base_t::value;
operator std::add_lvalue_reference_t<T>() {
return value_;
return this->base_t::value();
}
operator std::add_const_t<std::add_lvalue_reference_t<T>>() const {
return this->base_t::value();
}
};
template <typename T>
struct nested {
struct nested : private detail::ebco<T> {
private:
T value_;
using base_t = detail::ebco<T>;
public:
using nested_type = T;
@ -349,29 +370,17 @@ namespace sol {
nested(nested&&) = default;
nested& operator=(const nested&) = default;
nested& operator=(nested&&) = default;
template <typename Arg,
meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, nested>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
nested(Arg&& arg) : value_(std::forward<Arg>(arg)) {
}
template <typename Arg0, typename Arg1, typename... Args>
nested(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
}
T& value() & {
return value_;
}
using base_t::base_t;
T&& value() && {
return std::move(value_);
}
const T& value() const& {
return value_;
}
using base_t::value;
operator std::add_lvalue_reference_t<T>() {
return value_;
return this->base_t::value();
}
operator std::add_const_t<std::add_lvalue_reference_t<T>>() const {
return this->base_t::value();
}
};
@ -399,9 +408,9 @@ namespace sol {
}
template <typename T>
struct as_container_t {
struct as_container_t : private detail::ebco<T> {
private:
T value_;
using base_t = detail::ebco<T>;
public:
using type = T;
@ -411,42 +420,12 @@ namespace sol {
as_container_t(as_container_t&&) = default;
as_container_t& operator=(const as_container_t&) = default;
as_container_t& operator=(as_container_t&&) = default;
template <typename Arg,
meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_container_t>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
as_container_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {
}
template <typename Arg0, typename Arg1, typename... Args>
as_container_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
}
T& value() & {
return value_;
}
using base_t::base_t;
T&& value() && {
return std::move(value_);
}
using base_t::value;
const T& value() const& {
return value_;
}
};
template <typename T>
struct as_container_t<T&> {
private:
std::reference_wrapper<T> value_;
public:
as_container_t(T& value) : value_(value) {
}
T& value() {
return value_;
}
operator T&() {
operator std::add_lvalue_reference_t<T>() {
return value();
}
};
@ -457,9 +436,9 @@ namespace sol {
}
template <typename T>
struct push_invoke_t {
struct push_invoke_t : private detail::ebco<T> {
private:
T value_;
using base_t = detail::ebco<T>;
public:
push_invoke_t() = default;
@ -467,38 +446,10 @@ namespace sol {
push_invoke_t(push_invoke_t&&) = default;
push_invoke_t& operator=(const push_invoke_t&) = default;
push_invoke_t& operator=(push_invoke_t&&) = default;
template <typename Arg,
meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, push_invoke_t>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
push_invoke_t(Arg&& arg) : value_(std::forward<Arg>(arg)) {
}
template <typename Arg0, typename Arg1, typename... Args>
push_invoke_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : value_(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
}
T& value() & {
return value_;
}
using base_t::base_t;
T&& value() && {
return std::move(value_);
}
const T& value() const& {
return value_;
}
};
template <typename T>
struct push_invoke_t<T&> {
std::reference_wrapper<T> value_;
push_invoke_t(T& value) : value_(value) {
}
T& value() {
return value_;
}
using base_t::value;
};
template <typename Fx>
@ -506,6 +457,28 @@ namespace sol {
return push_invoke_t<Fx>(std::forward<Fx>(fx));
}
template <typename T>
struct forward_as_value_t : private detail::ebco<T> {
private:
using base_t = detail::ebco<T>;
public:
forward_as_value_t() = default;
forward_as_value_t(const forward_as_value_t&) = default;
forward_as_value_t(forward_as_value_t&&) = default;
forward_as_value_t& operator=(const forward_as_value_t&) = default;
forward_as_value_t& operator=(forward_as_value_t&&) = default;
using base_t::base_t;
using base_t::value;
};
template <typename T>
auto pass_as_value(T& value_ref_) {
return forward_as_value_t<T>(value_ref_);
}
struct override_value_t { };
constexpr inline override_value_t override_value = override_value_t();
struct update_if_empty_t { };
@ -1156,6 +1129,17 @@ namespace sol {
template <typename T>
constexpr inline bool has_internal_marker_v = has_internal_marker<T>::value;
// MSVC's decltype detection is broken, which breaks other
// parts of the code. So we add more workarounds. The moment it's fixed,
// we take it away and break everyone that doesn't upgrade.
template <typename T>
using is_msvc_callable_rigged = meta::any<meta::is_specialization_of<T, push_invoke_t>, meta::is_specialization_of<T, as_table_t>,
meta::is_specialization_of<T, forward_as_value_t>, meta::is_specialization_of<T, as_container_t>, meta::is_specialization_of<T, nested>,
meta::is_specialization_of<T, yielding_t>, meta::is_specialization_of<T, ebco>>;
template <typename T>
inline constexpr bool is_msvc_callable_rigged_v = is_msvc_callable_rigged<T>::value;
} // namespace detail
template <typename T>

View File

@ -828,7 +828,7 @@ namespace sol {
template <typename Iter>
static detail::error_result find_associative_lookup(std::false_type, lua_State* L, T& self, Iter&, std::size_t idx) {
idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) + deferred_uc::index_adjustment(L, self));
idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) - deferred_uc::index_adjustment(L, self));
return stack::push(L, idx);
}
@ -1401,7 +1401,7 @@ namespace sol {
using v_t = std::add_const_t<decltype(self[idx])>;
v_t v = self[idx];
if (v == value) {
idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) + deferred_uc::index_adjustment(L, self));
idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) - deferred_uc::index_adjustment(L, self));
return stack::push(L, idx);
}
}

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2020-12-16 20:25:14.474291 UTC
// This header was generated with sol v3.2.3 (revision 5b7cf9ad)
// Generated 2020-12-18 04:17:10.718684 UTC
// This header was generated with sol v3.2.3 (revision 561c90ab)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_CONFIG_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2020-12-16 20:25:14.452290 UTC
// This header was generated with sol v3.2.3 (revision 5b7cf9ad)
// Generated 2020-12-18 04:17:10.578992 UTC
// This header was generated with sol v3.2.3 (revision 561c90ab)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,8 @@ function(CREATE_TEST test_target_name test_name target_sol)
EXPORT_NAME sol2::${test_name})
target_link_libraries(${test_target_name}
PUBLIC Threads::Threads ${LUA_LIBRARIES} ${target_sol})
target_compile_definitions(${test_target_name}
PRIVATE SOL_ALL_SAFETIES_ON)
if (MSVC)
target_compile_options(${test_target_name}
PRIVATE /EHsc /std:c++latest /W4)

View File

@ -1,5 +1,3 @@
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
struct foo1000 {

View File

@ -1,5 +1,3 @@
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
int regression_1008() {

View File

@ -1,5 +1,3 @@
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
int regression_1067() {
@ -7,7 +5,7 @@ int regression_1067() {
lua.open_libraries(sol::lib::base);
lua["fct"] = std::function<int()> { []() { return 42; } };
lua.script("print(fct())");
sol::optional<sol::error> maybe_error = lua.safe_script("print(fct())");
return 0;
return maybe_error.has_value() ? 1 : 0;
}

View File

@ -0,0 +1,13 @@
#include <sol/sol.hpp>
int regression_1072() {
auto st = sol::state {};
// If you remove the capture, the problem goes away.
st["foo"] = [&] { throw std::runtime_error(""); };
sol::protected_function_result result = st.safe_script("foo()", sol::script_pass_on_error);
if (!result.valid()) {
sol::error err = result;
return 0;
}
return 1;
}

View File

@ -3,15 +3,26 @@
extern int regression_1000();
extern int regression_1008();
extern int regression_1067();
extern int regression_1072();
using f_ptr = int();
int trampoline(f_ptr* f) {
try {
return f();
}
catch (...) {
}
return 1;
}
int main(int, char*[]) {
using f_ptr = int (*)();
const f_ptr regressions[] = { &regression_1008, &regression_1000, &regression_1067 };
f_ptr* regressions[] = { &regression_1008, &regression_1000, &regression_1067, &regression_1072 };
const int sizeof_regressions = sizeof(regressions) / sizeof(regressions[0]);
int r = 0;
for (std::size_t i = 0; i < sizeof_regressions; ++i) {
f_ptr f = regressions[0];
r += static_cast<int>(f() != 0);
f_ptr* f = regressions[i];
r += static_cast<int>(trampoline(f) != 0);
}
return r;
}

View File

@ -836,10 +836,10 @@ TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/ref
};
lua.set_function("set_y", &decltype(objy)::operator(), std::ref(objy));
auto result1 = lua.safe_script("set_x(9)", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("set_y(9)", sol::script_pass_on_error);
REQUIRE(result2.valid());
sol::optional<sol::error> result1 = lua.safe_script("set_x(9)", sol::script_pass_on_error);
REQUIRE_FALSE(result1.has_value());
sol::optional<sol::error> result2 = lua.safe_script("set_y(9)", sol::script_pass_on_error);
REQUIRE_FALSE(result2.has_value());
REQUIRE(x == 9);
REQUIRE(y == 9);