mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Remove as many of the std::string error handlers as possible to avoid memory leaks in C mode
Add some checks for container usertypes that masquerade as convertible from tables Make sure shared_ptr-like types that are copyable are returned directly (but do not do this for move-only types)
This commit is contained in:
parent
88355fcdf8
commit
ce32549bc6
|
@ -147,7 +147,8 @@ namespace sol {
|
|||
typedef meta::tuple_types<typename traits::return_type> return_types;
|
||||
typedef typename traits::free_args_list args_list;
|
||||
// compile-time eliminate any functions that we know ahead of time are of improper arity
|
||||
if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
if constexpr (!traits::runtime_variadics_t::value
|
||||
&& meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
return overload_match_arity(types<Fxs...>(),
|
||||
std::index_sequence<In...>(),
|
||||
std::index_sequence<M...>(),
|
||||
|
@ -237,7 +238,8 @@ namespace sol {
|
|||
typedef meta::tuple_types<typename traits::return_type> return_types;
|
||||
typedef typename traits::free_args_list args_list;
|
||||
// compile-time eliminate any functions that we know ahead of time are of improper arity
|
||||
if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
if constexpr (!traits::runtime_variadics_t::value
|
||||
&& meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
return overload_match_arity(types<Fx1, Fxs...>(),
|
||||
std::index_sequence<I1, In...>(),
|
||||
std::index_sequence<M...>(),
|
||||
|
@ -373,6 +375,7 @@ namespace sol {
|
|||
}
|
||||
else {
|
||||
if constexpr (std::is_const_v<meta::unwrapped_t<T>>) {
|
||||
(void)f;
|
||||
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
|
||||
}
|
||||
else {
|
||||
|
@ -502,8 +505,13 @@ namespace sol {
|
|||
else {
|
||||
using returns_list = typename wrap::returns_list;
|
||||
using caller = typename wrap::caller;
|
||||
return stack::call_into_lua<checked, clean_stack>(
|
||||
returns_list(), types<>(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
return stack::call_into_lua<checked, clean_stack>(returns_list(),
|
||||
types<>(),
|
||||
L,
|
||||
boost + (is_variable ? 3 : 2),
|
||||
caller(),
|
||||
std::forward<Fx>(fx),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -727,8 +735,7 @@ namespace sol {
|
|||
|
||||
template <typename F, typename... Args>
|
||||
static int call(lua_State* L, F&& f, Args&&... args) {
|
||||
constexpr bool is_specialized = meta::any<
|
||||
std::is_same<U, detail::no_prop>,
|
||||
constexpr bool is_specialized = meta::any<std::is_same<U, detail::no_prop>,
|
||||
meta::is_specialization_of<U, var_wrapper>,
|
||||
meta::is_specialization_of<U, constructor_wrapper>,
|
||||
meta::is_specialization_of<U, constructor_list>,
|
||||
|
@ -861,7 +868,8 @@ namespace sol {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, bool clean_stack = true>
|
||||
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls,
|
||||
bool clean_stack = true>
|
||||
inline int call_user(lua_State* L) {
|
||||
auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));
|
||||
return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "types.hpp"
|
||||
#include "demangle.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace sol {
|
||||
|
||||
namespace detail {
|
||||
|
@ -46,21 +48,20 @@ namespace sol {
|
|||
constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment";
|
||||
constexpr const char* protected_function_error = "caught (...) unknown error during protected_function call";
|
||||
|
||||
inline void accumulate_and_mark(const std::string& n, std::string& addendum, int& marker) {
|
||||
inline void accumulate_and_mark(const std::string& n, std::string& aux_message, int& marker) {
|
||||
if (marker > 0) {
|
||||
addendum += ", ";
|
||||
aux_message += ", ";
|
||||
}
|
||||
addendum += n;
|
||||
aux_message += n;
|
||||
++marker;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline std::string associated_type_name(lua_State* L, int index, type t) {
|
||||
switch (t) {
|
||||
case type::poly:
|
||||
return "anything";
|
||||
case type::userdata:
|
||||
{
|
||||
case type::userdata: {
|
||||
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
|
||||
luaL_checkstack(L, 2, "not enough space to push get the type name");
|
||||
#endif // make sure stack doesn't overflow
|
||||
|
@ -81,63 +82,67 @@ namespace sol {
|
|||
return lua_typename(L, static_cast<int>(t));
|
||||
}
|
||||
|
||||
inline int type_panic_string(lua_State* L, int index, type expected, type actual, const std::string& message = "") noexcept(false) {
|
||||
const char* err = message.empty() ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s";
|
||||
std::string actualname = associated_type_name(L, index, actual);
|
||||
return luaL_error(L, err, index,
|
||||
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
|
||||
actualname.c_str(),
|
||||
message.c_str());
|
||||
inline int push_type_panic_string(lua_State* L, int index, type expected, type actual, string_view message, string_view aux_message) noexcept {
|
||||
const char* err = message.size() == 0
|
||||
? (aux_message.size() == 0 ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s")
|
||||
: "stack index %d, expected %s, received %s: %s %s";
|
||||
const char* type_name = expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected));
|
||||
{
|
||||
std::string actual_name = associated_type_name(L, index, actual);
|
||||
lua_pushfstring(L, err, index, type_name, actual_name.c_str(), message.data(), aux_message.data());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int type_panic_string(lua_State* L, int index, type expected, type actual, string_view message = "") noexcept(false) {
|
||||
push_type_panic_string(L, index, expected, actual, message, "");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) {
|
||||
const char* err = message == nullptr || (std::char_traits<char>::length(message) == 0) ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s";
|
||||
std::string actualname = associated_type_name(L, index, actual);
|
||||
return luaL_error(L, err, index,
|
||||
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
|
||||
actualname.c_str(),
|
||||
message);
|
||||
push_type_panic_string(L, index, expected, actual, message == nullptr ? "" : message, "");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
struct type_panic_t {
|
||||
int operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) {
|
||||
return type_panic_c_str(L, index, expected, actual, nullptr);
|
||||
}
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const char* message) const noexcept(false) {
|
||||
return type_panic_c_str(L, index, expected, actual, message);
|
||||
}
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
return type_panic_string(L, index, expected, actual, message);
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
return type_panic_c_str(L, index, expected, actual, message.data());
|
||||
}
|
||||
};
|
||||
|
||||
const type_panic_t type_panic = {};
|
||||
|
||||
struct constructor_handler {
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
std::string str = "(type check failed in constructor)";
|
||||
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str);
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
push_type_panic_string(L, index, expected, actual, message, "(type check failed in constructor)");
|
||||
return lua_error(L);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F = void>
|
||||
struct argument_handler {
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
std::string str = "(bad argument to variable or function call)";
|
||||
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str );
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
push_type_panic_string(L, index, expected, actual, message, "(bad argument to variable or function call)");
|
||||
return lua_error(L);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct argument_handler<types<R, Args...>> {
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
std::string addendum = "(bad argument into '";
|
||||
addendum += detail::demangle<R>();
|
||||
addendum += "(";
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
{
|
||||
std::string aux_message = "(bad argument into '";
|
||||
aux_message += detail::demangle<R>();
|
||||
aux_message += "(";
|
||||
int marker = 0;
|
||||
(void)detail::swallow{int(), (detail::accumulate_and_mark(detail::demangle<Args>(), addendum, marker), int())...};
|
||||
addendum += ")')";
|
||||
return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + addendum);
|
||||
(void)detail::swallow{ int(), (detail::accumulate_and_mark(detail::demangle<Args>(), aux_message, marker), int())... };
|
||||
aux_message += ")')";
|
||||
push_type_panic_string(L, index, expected, actual, message, aux_message);
|
||||
}
|
||||
return lua_error(L);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -71,9 +71,9 @@ namespace sol {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
inline decltype(auto) deref_non_pointer(T&& item) {
|
||||
inline decltype(auto) deref_move_only(T&& item) {
|
||||
using Tu = meta::unqualified_t<T>;
|
||||
if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu>) {
|
||||
if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu> && !std::is_copy_constructible_v<Tu>) {
|
||||
return *std::forward<T>(item);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -491,7 +491,7 @@ namespace sol {
|
|||
captured_type;
|
||||
typedef typename meta::iterator_tag<iterator>::type iterator_category;
|
||||
typedef std::is_same<iterator_category, std::input_iterator_tag> is_input_iterator;
|
||||
typedef meta::conditional_t<is_input_iterator::value, V, decltype(detail::deref_non_pointer(std::declval<captured_type>()))> push_type;
|
||||
typedef meta::conditional_t<is_input_iterator::value, V, decltype(detail::deref_move_only(std::declval<captured_type>()))> push_type;
|
||||
typedef std::is_copy_assignable<V> is_copyable;
|
||||
typedef meta::neg<meta::any<std::is_const<V>, std::is_const<std::remove_reference_t<iterator_return>>, meta::neg<is_copyable>>> is_writable;
|
||||
typedef meta::unqualified_t<decltype(get_key(is_associative(), std::declval<std::add_lvalue_reference_t<value_type>>()))> key_type;
|
||||
|
@ -564,12 +564,12 @@ namespace sol {
|
|||
template <typename Iter>
|
||||
static detail::error_result get_associative(std::true_type, lua_State* L, Iter& it) {
|
||||
decltype(auto) v = *it;
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(v.second));
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(v.second));
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
static detail::error_result get_associative(std::false_type, lua_State* L, Iter& it) {
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it));
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it));
|
||||
}
|
||||
|
||||
static detail::error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {
|
||||
|
@ -1144,7 +1144,7 @@ namespace sol {
|
|||
else {
|
||||
p = stack::push_reference(L, it->first);
|
||||
}
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(it->second));
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(it->second));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -1165,7 +1165,7 @@ namespace sol {
|
|||
else {
|
||||
p = stack::stack_detail::push_reference(L, k + 1);
|
||||
}
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it));
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -1391,7 +1391,7 @@ namespace sol {
|
|||
}
|
||||
int p;
|
||||
p = stack::push(L, k + 1);
|
||||
p += stack::push_reference(L, detail::deref_non_pointer(*it));
|
||||
p += stack::push_reference(L, detail::deref_move_only(*it));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -1424,7 +1424,7 @@ namespace sol {
|
|||
if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value) || idx < 0) {
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
return stack::push_reference(L, detail::deref_non_pointer(self[idx]));
|
||||
return stack::push_reference(L, detail::deref_move_only(self[idx]));
|
||||
}
|
||||
|
||||
static int index_get(lua_State* L) {
|
||||
|
|
|
@ -175,10 +175,7 @@ namespace sol { namespace u_detail {
|
|||
index_call_storage* p_ics = nullptr;
|
||||
usertype_storage_base* p_usb = nullptr;
|
||||
void* p_derived_usb = nullptr;
|
||||
lua_CFunction idx_call = nullptr,
|
||||
new_idx_call = nullptr,
|
||||
meta_idx_call = nullptr,
|
||||
meta_new_idx_call = nullptr;
|
||||
lua_CFunction idx_call = nullptr, new_idx_call = nullptr, meta_idx_call = nullptr, meta_new_idx_call = nullptr;
|
||||
change_indexing_mem_func change_indexing;
|
||||
|
||||
void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {
|
||||
|
@ -196,14 +193,7 @@ namespace sol { namespace u_detail {
|
|||
int fast_index_table_push = fast_index_table.push();
|
||||
stack_reference t(L, -fast_index_table_push);
|
||||
if (poison_indexing) {
|
||||
(usb.*change_indexing)(L,
|
||||
smt,
|
||||
p_derived_usb,
|
||||
t,
|
||||
idx_call,
|
||||
new_idx_call,
|
||||
meta_idx_call,
|
||||
meta_new_idx_call);
|
||||
(usb.*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call);
|
||||
}
|
||||
if (is_destruction
|
||||
&& (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named
|
||||
|
@ -264,14 +254,7 @@ namespace sol { namespace u_detail {
|
|||
stack::set_field(L, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index());
|
||||
stack::set_field(L, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index());
|
||||
// change indexing, forcefully
|
||||
(p_usb->*change_indexing)(L,
|
||||
smt,
|
||||
p_derived_usb,
|
||||
t,
|
||||
idx_call,
|
||||
new_idx_call,
|
||||
meta_idx_call,
|
||||
meta_new_idx_call);
|
||||
(p_usb->*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call);
|
||||
t.pop();
|
||||
}
|
||||
};
|
||||
|
@ -279,7 +262,8 @@ namespace sol { namespace u_detail {
|
|||
struct binding_data_equals {
|
||||
void* binding_data;
|
||||
|
||||
binding_data_equals(void* b) : binding_data(b) {}
|
||||
binding_data_equals(void* b) : binding_data(b) {
|
||||
}
|
||||
|
||||
bool operator()(const std::unique_ptr<binding_base>& ptr) const {
|
||||
return binding_data == ptr->data();
|
||||
|
@ -644,6 +628,7 @@ namespace sol { namespace u_detail {
|
|||
using Binding = binding<KeyU, ValueU, T>;
|
||||
using is_var_bind = is_variable_binding<ValueU>;
|
||||
if constexpr (std::is_same_v<KeyU, call_construction>) {
|
||||
(void)key;
|
||||
std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value));
|
||||
Binding& b = *p_binding;
|
||||
this->storage.push_back(std::move(p_binding));
|
||||
|
@ -689,9 +674,10 @@ namespace sol { namespace u_detail {
|
|||
void* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this));
|
||||
index_call_storage ics;
|
||||
ics.binding_data = b.data();
|
||||
ics.index = is_index || is_static_index ? &Binding::template call_with_<true, is_var_bind::value> : &Binding::template index_call_with_<true, is_var_bind::value>;
|
||||
ics.new_index
|
||||
= is_new_index || is_static_new_index ? &Binding::template call_with_<false, is_var_bind::value> : &Binding::template index_call_with_<false, is_var_bind::value>;
|
||||
ics.index = is_index || is_static_index ? &Binding::template call_with_<true, is_var_bind::value>
|
||||
: &Binding::template index_call_with_<true, is_var_bind::value>;
|
||||
ics.new_index = is_new_index || is_static_new_index ? &Binding::template call_with_<false, is_var_bind::value>
|
||||
: &Binding::template index_call_with_<false, is_var_bind::value>;
|
||||
|
||||
string_for_each_metatable_func for_each_fx;
|
||||
for_each_fx.is_destruction = is_destruction;
|
||||
|
|
|
@ -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 2019-10-02 08:43:39.434050 UTC
|
||||
// This header was generated with sol v3.0.3 (revision 908074e)
|
||||
// Generated 2019-11-09 04:52:35.824332 UTC
|
||||
// This header was generated with sol v3.0.3 (revision 88355fc)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
|
||||
|
|
|
@ -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 2019-10-02 08:43:38.869924 UTC
|
||||
// This header was generated with sol v3.0.3 (revision 908074e)
|
||||
// Generated 2019-11-09 04:52:35.317324 UTC
|
||||
// This header was generated with sol v3.0.3 (revision 88355fc)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||
|
@ -1228,9 +1228,9 @@ namespace sol {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
inline decltype(auto) deref_non_pointer(T&& item) {
|
||||
inline decltype(auto) deref_move_only(T&& item) {
|
||||
using Tu = meta::unqualified_t<T>;
|
||||
if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu>) {
|
||||
if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu> && !std::is_copy_constructible_v<Tu>) {
|
||||
return *std::forward<T>(item);
|
||||
}
|
||||
else {
|
||||
|
@ -8266,6 +8266,8 @@ namespace sol {
|
|||
|
||||
// beginning of sol/error_handler.hpp
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace sol {
|
||||
|
||||
namespace detail {
|
||||
|
@ -8285,21 +8287,20 @@ namespace sol {
|
|||
constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment";
|
||||
constexpr const char* protected_function_error = "caught (...) unknown error during protected_function call";
|
||||
|
||||
inline void accumulate_and_mark(const std::string& n, std::string& addendum, int& marker) {
|
||||
inline void accumulate_and_mark(const std::string& n, std::string& aux_message, int& marker) {
|
||||
if (marker > 0) {
|
||||
addendum += ", ";
|
||||
aux_message += ", ";
|
||||
}
|
||||
addendum += n;
|
||||
aux_message += n;
|
||||
++marker;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline std::string associated_type_name(lua_State* L, int index, type t) {
|
||||
switch (t) {
|
||||
case type::poly:
|
||||
return "anything";
|
||||
case type::userdata:
|
||||
{
|
||||
case type::userdata: {
|
||||
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
|
||||
luaL_checkstack(L, 2, "not enough space to push get the type name");
|
||||
#endif // make sure stack doesn't overflow
|
||||
|
@ -8320,63 +8321,67 @@ namespace sol {
|
|||
return lua_typename(L, static_cast<int>(t));
|
||||
}
|
||||
|
||||
inline int type_panic_string(lua_State* L, int index, type expected, type actual, const std::string& message = "") noexcept(false) {
|
||||
const char* err = message.empty() ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s";
|
||||
std::string actualname = associated_type_name(L, index, actual);
|
||||
return luaL_error(L, err, index,
|
||||
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
|
||||
actualname.c_str(),
|
||||
message.c_str());
|
||||
inline int push_type_panic_string(lua_State* L, int index, type expected, type actual, string_view message, string_view aux_message) noexcept {
|
||||
const char* err = message.size() == 0
|
||||
? (aux_message.size() == 0 ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s")
|
||||
: "stack index %d, expected %s, received %s: %s %s";
|
||||
const char* type_name = expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected));
|
||||
{
|
||||
std::string actual_name = associated_type_name(L, index, actual);
|
||||
lua_pushfstring(L, err, index, type_name, actual_name.c_str(), message.data(), aux_message.data());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int type_panic_string(lua_State* L, int index, type expected, type actual, string_view message = "") noexcept(false) {
|
||||
push_type_panic_string(L, index, expected, actual, message, "");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) {
|
||||
const char* err = message == nullptr || (std::char_traits<char>::length(message) == 0) ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s";
|
||||
std::string actualname = associated_type_name(L, index, actual);
|
||||
return luaL_error(L, err, index,
|
||||
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
|
||||
actualname.c_str(),
|
||||
message);
|
||||
push_type_panic_string(L, index, expected, actual, message == nullptr ? "" : message, "");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
struct type_panic_t {
|
||||
int operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) {
|
||||
return type_panic_c_str(L, index, expected, actual, nullptr);
|
||||
}
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const char* message) const noexcept(false) {
|
||||
return type_panic_c_str(L, index, expected, actual, message);
|
||||
}
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
return type_panic_string(L, index, expected, actual, message);
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
return type_panic_c_str(L, index, expected, actual, message.data());
|
||||
}
|
||||
};
|
||||
|
||||
const type_panic_t type_panic = {};
|
||||
|
||||
struct constructor_handler {
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
std::string str = "(type check failed in constructor)";
|
||||
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str);
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
push_type_panic_string(L, index, expected, actual, message, "(type check failed in constructor)");
|
||||
return lua_error(L);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F = void>
|
||||
struct argument_handler {
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
std::string str = "(bad argument to variable or function call)";
|
||||
return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str );
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
push_type_panic_string(L, index, expected, actual, message, "(bad argument to variable or function call)");
|
||||
return lua_error(L);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct argument_handler<types<R, Args...>> {
|
||||
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
|
||||
std::string addendum = "(bad argument into '";
|
||||
addendum += detail::demangle<R>();
|
||||
addendum += "(";
|
||||
int operator()(lua_State* L, int index, type expected, type actual, string_view message) const noexcept(false) {
|
||||
{
|
||||
std::string aux_message = "(bad argument into '";
|
||||
aux_message += detail::demangle<R>();
|
||||
aux_message += "(";
|
||||
int marker = 0;
|
||||
(void)detail::swallow{int(), (detail::accumulate_and_mark(detail::demangle<Args>(), addendum, marker), int())...};
|
||||
addendum += ")')";
|
||||
return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + addendum);
|
||||
(void)detail::swallow{ int(), (detail::accumulate_and_mark(detail::demangle<Args>(), aux_message, marker), int())... };
|
||||
aux_message += ")')";
|
||||
push_type_panic_string(L, index, expected, actual, message, aux_message);
|
||||
}
|
||||
return lua_error(L);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -16241,7 +16246,8 @@ namespace sol {
|
|||
typedef meta::tuple_types<typename traits::return_type> return_types;
|
||||
typedef typename traits::free_args_list args_list;
|
||||
// compile-time eliminate any functions that we know ahead of time are of improper arity
|
||||
if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
if constexpr (!traits::runtime_variadics_t::value
|
||||
&& meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
return overload_match_arity(types<Fxs...>(),
|
||||
std::index_sequence<In...>(),
|
||||
std::index_sequence<M...>(),
|
||||
|
@ -16331,7 +16337,8 @@ namespace sol {
|
|||
typedef meta::tuple_types<typename traits::return_type> return_types;
|
||||
typedef typename traits::free_args_list args_list;
|
||||
// compile-time eliminate any functions that we know ahead of time are of improper arity
|
||||
if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
if constexpr (!traits::runtime_variadics_t::value
|
||||
&& meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
|
||||
return overload_match_arity(types<Fx1, Fxs...>(),
|
||||
std::index_sequence<I1, In...>(),
|
||||
std::index_sequence<M...>(),
|
||||
|
@ -16467,6 +16474,7 @@ namespace sol {
|
|||
}
|
||||
else {
|
||||
if constexpr (std::is_const_v<meta::unwrapped_t<T>>) {
|
||||
(void)f;
|
||||
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
|
||||
}
|
||||
else {
|
||||
|
@ -16596,8 +16604,13 @@ namespace sol {
|
|||
else {
|
||||
using returns_list = typename wrap::returns_list;
|
||||
using caller = typename wrap::caller;
|
||||
return stack::call_into_lua<checked, clean_stack>(
|
||||
returns_list(), types<>(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
return stack::call_into_lua<checked, clean_stack>(returns_list(),
|
||||
types<>(),
|
||||
L,
|
||||
boost + (is_variable ? 3 : 2),
|
||||
caller(),
|
||||
std::forward<Fx>(fx),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -16821,8 +16834,7 @@ namespace sol {
|
|||
|
||||
template <typename F, typename... Args>
|
||||
static int call(lua_State* L, F&& f, Args&&... args) {
|
||||
constexpr bool is_specialized = meta::any<
|
||||
std::is_same<U, detail::no_prop>,
|
||||
constexpr bool is_specialized = meta::any<std::is_same<U, detail::no_prop>,
|
||||
meta::is_specialization_of<U, var_wrapper>,
|
||||
meta::is_specialization_of<U, constructor_wrapper>,
|
||||
meta::is_specialization_of<U, constructor_list>,
|
||||
|
@ -16955,7 +16967,8 @@ namespace sol {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, bool clean_stack = true>
|
||||
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls,
|
||||
bool clean_stack = true>
|
||||
inline int call_user(lua_State* L) {
|
||||
auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));
|
||||
return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
|
||||
|
@ -19522,7 +19535,7 @@ namespace sol {
|
|||
captured_type;
|
||||
typedef typename meta::iterator_tag<iterator>::type iterator_category;
|
||||
typedef std::is_same<iterator_category, std::input_iterator_tag> is_input_iterator;
|
||||
typedef meta::conditional_t<is_input_iterator::value, V, decltype(detail::deref_non_pointer(std::declval<captured_type>()))> push_type;
|
||||
typedef meta::conditional_t<is_input_iterator::value, V, decltype(detail::deref_move_only(std::declval<captured_type>()))> push_type;
|
||||
typedef std::is_copy_assignable<V> is_copyable;
|
||||
typedef meta::neg<meta::any<std::is_const<V>, std::is_const<std::remove_reference_t<iterator_return>>, meta::neg<is_copyable>>> is_writable;
|
||||
typedef meta::unqualified_t<decltype(get_key(is_associative(), std::declval<std::add_lvalue_reference_t<value_type>>()))> key_type;
|
||||
|
@ -19595,12 +19608,12 @@ namespace sol {
|
|||
template <typename Iter>
|
||||
static detail::error_result get_associative(std::true_type, lua_State* L, Iter& it) {
|
||||
decltype(auto) v = *it;
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(v.second));
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(v.second));
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
static detail::error_result get_associative(std::false_type, lua_State* L, Iter& it) {
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it));
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it));
|
||||
}
|
||||
|
||||
static detail::error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {
|
||||
|
@ -20175,7 +20188,7 @@ namespace sol {
|
|||
else {
|
||||
p = stack::push_reference(L, it->first);
|
||||
}
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(it->second));
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(it->second));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -20196,7 +20209,7 @@ namespace sol {
|
|||
else {
|
||||
p = stack::stack_detail::push_reference(L, k + 1);
|
||||
}
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it));
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref_move_only(*it));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -20422,7 +20435,7 @@ namespace sol {
|
|||
}
|
||||
int p;
|
||||
p = stack::push(L, k + 1);
|
||||
p += stack::push_reference(L, detail::deref_non_pointer(*it));
|
||||
p += stack::push_reference(L, detail::deref_move_only(*it));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -20455,7 +20468,7 @@ namespace sol {
|
|||
if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value) || idx < 0) {
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
return stack::push_reference(L, detail::deref_non_pointer(self[idx]));
|
||||
return stack::push_reference(L, detail::deref_move_only(self[idx]));
|
||||
}
|
||||
|
||||
static int index_get(lua_State* L) {
|
||||
|
@ -21254,10 +21267,7 @@ namespace sol { namespace u_detail {
|
|||
index_call_storage* p_ics = nullptr;
|
||||
usertype_storage_base* p_usb = nullptr;
|
||||
void* p_derived_usb = nullptr;
|
||||
lua_CFunction idx_call = nullptr,
|
||||
new_idx_call = nullptr,
|
||||
meta_idx_call = nullptr,
|
||||
meta_new_idx_call = nullptr;
|
||||
lua_CFunction idx_call = nullptr, new_idx_call = nullptr, meta_idx_call = nullptr, meta_new_idx_call = nullptr;
|
||||
change_indexing_mem_func change_indexing;
|
||||
|
||||
void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {
|
||||
|
@ -21275,14 +21285,7 @@ namespace sol { namespace u_detail {
|
|||
int fast_index_table_push = fast_index_table.push();
|
||||
stack_reference t(L, -fast_index_table_push);
|
||||
if (poison_indexing) {
|
||||
(usb.*change_indexing)(L,
|
||||
smt,
|
||||
p_derived_usb,
|
||||
t,
|
||||
idx_call,
|
||||
new_idx_call,
|
||||
meta_idx_call,
|
||||
meta_new_idx_call);
|
||||
(usb.*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call);
|
||||
}
|
||||
if (is_destruction
|
||||
&& (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named
|
||||
|
@ -21343,14 +21346,7 @@ namespace sol { namespace u_detail {
|
|||
stack::set_field(L, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index());
|
||||
stack::set_field(L, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index());
|
||||
// change indexing, forcefully
|
||||
(p_usb->*change_indexing)(L,
|
||||
smt,
|
||||
p_derived_usb,
|
||||
t,
|
||||
idx_call,
|
||||
new_idx_call,
|
||||
meta_idx_call,
|
||||
meta_new_idx_call);
|
||||
(p_usb->*change_indexing)(L, smt, p_derived_usb, t, idx_call, new_idx_call, meta_idx_call, meta_new_idx_call);
|
||||
t.pop();
|
||||
}
|
||||
};
|
||||
|
@ -21358,7 +21354,8 @@ namespace sol { namespace u_detail {
|
|||
struct binding_data_equals {
|
||||
void* binding_data;
|
||||
|
||||
binding_data_equals(void* b) : binding_data(b) {}
|
||||
binding_data_equals(void* b) : binding_data(b) {
|
||||
}
|
||||
|
||||
bool operator()(const std::unique_ptr<binding_base>& ptr) const {
|
||||
return binding_data == ptr->data();
|
||||
|
@ -21723,6 +21720,7 @@ namespace sol { namespace u_detail {
|
|||
using Binding = binding<KeyU, ValueU, T>;
|
||||
using is_var_bind = is_variable_binding<ValueU>;
|
||||
if constexpr (std::is_same_v<KeyU, call_construction>) {
|
||||
(void)key;
|
||||
std::unique_ptr<Binding> p_binding = std::make_unique<Binding>(std::forward<Value>(value));
|
||||
Binding& b = *p_binding;
|
||||
this->storage.push_back(std::move(p_binding));
|
||||
|
@ -21768,9 +21766,10 @@ namespace sol { namespace u_detail {
|
|||
void* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this));
|
||||
index_call_storage ics;
|
||||
ics.binding_data = b.data();
|
||||
ics.index = is_index || is_static_index ? &Binding::template call_with_<true, is_var_bind::value> : &Binding::template index_call_with_<true, is_var_bind::value>;
|
||||
ics.new_index
|
||||
= is_new_index || is_static_new_index ? &Binding::template call_with_<false, is_var_bind::value> : &Binding::template index_call_with_<false, is_var_bind::value>;
|
||||
ics.index = is_index || is_static_index ? &Binding::template call_with_<true, is_var_bind::value>
|
||||
: &Binding::template index_call_with_<true, is_var_bind::value>;
|
||||
ics.new_index = is_new_index || is_static_new_index ? &Binding::template call_with_<false, is_var_bind::value>
|
||||
: &Binding::template index_call_with_<false, is_var_bind::value>;
|
||||
|
||||
string_for_each_metatable_func for_each_fx;
|
||||
for_each_fx.is_destruction = is_destruction;
|
||||
|
|
47
tests/runtime_tests/source/container.usertype_check.cpp
Normal file
47
tests/runtime_tests/source/container.usertype_check.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
// sol3
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2019 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "sol_test.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
|
||||
struct user_container_type : public std::vector<int> {
|
||||
typedef std::vector<int> base_t;
|
||||
using base_t::base_t;
|
||||
};
|
||||
|
||||
TEST_CASE("usertype/container checking fake container", "A container should not respond yes in .is<> to every table in Lua") {
|
||||
sol::state lua;
|
||||
sol::stack_guard luasg(lua);
|
||||
|
||||
sol::optional<sol::error> err0 = lua.safe_script("a = {}");
|
||||
REQUIRE_FALSE(err0.has_value());
|
||||
|
||||
sol::object a = lua["a"];
|
||||
REQUIRE(a.is<user_container_type>());
|
||||
REQUIRE_FALSE(a.is<user_container_type&>());
|
||||
REQUIRE_FALSE(a.is<user_container_type&&>());
|
||||
REQUIRE_FALSE(a.is<const user_container_type&>());
|
||||
REQUIRE_FALSE(a.is<const user_container_type&&>());
|
||||
}
|
|
@ -27,6 +27,17 @@
|
|||
|
||||
#include <catch.hpp>
|
||||
|
||||
struct unique_user_Display {
|
||||
int value = 5;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<unique_user_Display>> unique_user_foo() {
|
||||
return { std::make_shared<unique_user_Display>(), std::make_shared<unique_user_Display>(), std::make_shared<unique_user_Display>() };
|
||||
}
|
||||
|
||||
int unique_user_bar(std::shared_ptr<unique_user_Display> item) {
|
||||
return item->value;
|
||||
}
|
||||
|
||||
struct factory_test {
|
||||
private:
|
||||
|
@ -171,3 +182,15 @@ TEST_CASE("usertype/unique void pointers", "can compile shared_ptr<void> types a
|
|||
auto result = lua.safe_script("f(s)", sol::script_pass_on_error);
|
||||
REQUIRE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/unique containers", "copyable unique usertypes in containers are just fine and do not deref/decay") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua["foo"] = unique_user_foo;
|
||||
lua["bar"] = unique_user_bar;
|
||||
sol::optional<sol::error> err0 = lua.safe_script("v3 = foo()");
|
||||
REQUIRE_FALSE(err0.has_value());
|
||||
sol::optional<sol::error> err1 = lua.safe_script("assert(bar(v3[1]) == 5)");
|
||||
REQUIRE_FALSE(err1.has_value());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user