diff --git a/include/sol/call.hpp b/include/sol/call.hpp index 10015416..9bc514d4 100644 --- a/include/sol/call.hpp +++ b/include/sol/call.hpp @@ -147,7 +147,8 @@ namespace sol { typedef meta::tuple_types 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...>::value) { + if constexpr (!traits::runtime_variadics_t::value + && meta::find_in_pack_v, meta::index_value...>::value) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), @@ -161,25 +162,25 @@ namespace sol { if constexpr (!traits::runtime_variadics_t::value) { if (traits::free_arity != fxarity) { return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } } stack::record tracking{}; if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } return matchfx(types(), meta::index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } @@ -237,7 +238,8 @@ namespace sol { typedef meta::tuple_types 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...>::value) { + if constexpr (!traits::runtime_variadics_t::value + && meta::find_in_pack_v, meta::index_value...>::value) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), @@ -251,25 +253,25 @@ namespace sol { if constexpr (!traits::runtime_variadics_t::value) { if (traits::free_arity != fxarity) { return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } } stack::record tracking{}; if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { - return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + return overload_match_arity(types(), + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } return matchfx(types(), meta::index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } @@ -330,7 +332,7 @@ namespace sol { template static int call(lua_State* L, Fx&& f, Args&&... args) { - if constexpr(is_lua_reference_v>) { + if constexpr (is_lua_reference_v>) { if constexpr (is_index) { return stack::push(L, std::forward(f), std::forward(args)...); } @@ -373,6 +375,7 @@ namespace sol { } else { if constexpr (std::is_const_v>) { + (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( - returns_list(), types<>(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), std::forward(args)...); + return stack::call_into_lua(returns_list(), + types<>(), + L, + boost + (is_variable ? 3 : 2), + caller(), + std::forward(fx), + std::forward(args)...); } } else { @@ -528,16 +536,16 @@ namespace sol { using caller = typename wrap::caller; if constexpr (sizeof...(Args) > 0) { return stack::call_into_lua(types(), - args_list(), - L, - boost + (is_variable ? 3 : 2), - caller(), - std::forward(fx), - std::forward(args)...); + args_list(), + L, + boost + (is_variable ? 3 : 2), + caller(), + std::forward(fx), + std::forward(args)...); } else { using Ta = meta::conditional_t, object_type, T>; - #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE +#if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE auto maybeo = stack::check_get(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { @@ -547,12 +555,12 @@ namespace sol { } object_type* po = static_cast(maybeo.value()); object_type& o = *po; - #else +#else object_type& o = static_cast(*stack::get>(L, 1)); - #endif // Safety +#endif // Safety return stack::call_into_lua( - types(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), o); + types(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), o); } } } @@ -727,8 +735,7 @@ namespace sol { template static int call(lua_State* L, F&& f, Args&&... args) { - constexpr bool is_specialized = meta::any< - std::is_same, + constexpr bool is_specialized = meta::any, meta::is_specialization_of, meta::is_specialization_of, meta::is_specialization_of, @@ -747,7 +754,7 @@ namespace sol { } else { constexpr bool non_class_object_type = meta::any, - meta::boolean>::value != type::userdata>>::value; + meta::boolean>::value != type::userdata>>::value; if constexpr (non_class_object_type) { // The type being void means we don't have any arguments, so it might be a free functions? using args_list = typename traits_type::free_args_list; @@ -861,7 +868,8 @@ namespace sol { } } - template + template inline int call_user(lua_State* L) { auto& fx = stack::unqualified_get>(L, upvalue_index(start)); return call_wrapped(L, fx); diff --git a/include/sol/error_handler.hpp b/include/sol/error_handler.hpp index 66eb6b1f..7e019cc9 100644 --- a/include/sol/error_handler.hpp +++ b/include/sol/error_handler.hpp @@ -1,4 +1,4 @@ -// sol3 +// sol3 // The MIT License (MIT) @@ -27,6 +27,8 @@ #include "types.hpp" #include "demangle.hpp" +#include + 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(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(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(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::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(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 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 struct argument_handler> { - 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(); - addendum += "("; - int marker = 0; - (void)detail::swallow{int(), (detail::accumulate_and_mark(detail::demangle(), addendum, marker), int())...}; - addendum += ")')"; - return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + 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(); + aux_message += "("; + int marker = 0; + (void)detail::swallow{ int(), (detail::accumulate_and_mark(detail::demangle(), aux_message, marker), int())... }; + aux_message += ")')"; + push_type_panic_string(L, index, expected, actual, message, aux_message); + } + return lua_error(L); } }; diff --git a/include/sol/pointer_like.hpp b/include/sol/pointer_like.hpp index 054aee5a..569cf42e 100644 --- a/include/sol/pointer_like.hpp +++ b/include/sol/pointer_like.hpp @@ -71,9 +71,9 @@ namespace sol { } template - inline decltype(auto) deref_non_pointer(T&& item) { + inline decltype(auto) deref_move_only(T&& item) { using Tu = meta::unqualified_t; - if constexpr (meta::is_pointer_like_v && !std::is_pointer_v) { + if constexpr (meta::is_pointer_like_v && !std::is_pointer_v && !std::is_copy_constructible_v) { return *std::forward(item); } else { diff --git a/include/sol/usertype_container.hpp b/include/sol/usertype_container.hpp index b05494eb..d161a8bc 100644 --- a/include/sol/usertype_container.hpp +++ b/include/sol/usertype_container.hpp @@ -491,7 +491,7 @@ namespace sol { captured_type; typedef typename meta::iterator_tag::type iterator_category; typedef std::is_same is_input_iterator; - typedef meta::conditional_t()))> push_type; + typedef meta::conditional_t()))> push_type; typedef std::is_copy_assignable is_copyable; typedef meta::neg, std::is_const>, meta::neg>> is_writable; typedef meta::unqualified_t>()))> key_type; @@ -564,12 +564,12 @@ namespace sol { template static detail::error_result get_associative(std::true_type, lua_State* L, Iter& it) { decltype(auto) v = *it; - return stack::stack_detail::push_reference(L, detail::deref_non_pointer(v.second)); + return stack::stack_detail::push_reference(L, detail::deref_move_only(v.second)); } template static detail::error_result get_associative(std::false_type, lua_State* L, Iter& it) { - return stack::stack_detail::push_reference(L, detail::deref_non_pointer(*it)); + return stack::stack_detail::push_reference(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(L, detail::deref_non_pointer(it->second)); + p += stack::stack_detail::push_reference(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(L, detail::deref_non_pointer(*it)); + p += stack::stack_detail::push_reference(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::extent::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) { diff --git a/include/sol/usertype_storage.hpp b/include/sol/usertype_storage.hpp index e646966b..1b0ca1de 100644 --- a/include/sol/usertype_storage.hpp +++ b/include/sol/usertype_storage.hpp @@ -175,17 +175,14 @@ 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) { std::string& key = *p_key; usertype_storage_base& usb = *p_usb; index_call_storage& ics = *p_ics; - + if (smt == submetatable_type::named) { // do not override __call or // other specific meta functions on named metatable: @@ -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(base_class_check_func), t.stack_index()); stack::set_field(L, detail::base_class_cast_key(), reinterpret_cast(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& ptr) const { return binding_data == ptr->data(); @@ -446,7 +430,7 @@ namespace sol { namespace u_detail { type_table = lua_nil; gc_names_table = lua_nil; named_metatable = lua_nil; - + storage.clear(); string_keys.clear(); auxiliary_keys.clear(); @@ -466,7 +450,7 @@ namespace sol { namespace u_detail { #else optional&> maybe_base_storage = maybe_get_usertype_storage(L); if (static_cast(maybe_base_storage)) { - base_result = self_index_call(bases(), L, *maybe_base_storage); + base_result = self_index_call(bases(), L, *maybe_base_storage); keep_going = base_result == base_walking_failed_index; } #endif // Fast versus slow, safe base lookup @@ -504,7 +488,7 @@ namespace sol { namespace u_detail { } } if (target != nullptr) { - if constexpr(is_new_index) { + if constexpr (is_new_index) { // set value and return *target = reference(L, 3); return 0; @@ -633,7 +617,7 @@ namespace sol { namespace u_detail { }; template - inline int destruct_usertype_storage (lua_State* L) { + inline int destruct_usertype_storage(lua_State* L) { return detail::user_alloc_destruct>(L); } @@ -644,6 +628,7 @@ namespace sol { namespace u_detail { using Binding = binding; using is_var_bind = is_variable_binding; if constexpr (std::is_same_v) { + (void)key; std::unique_ptr p_binding = std::make_unique(std::forward(value)); Binding& b = *p_binding; this->storage.push_back(std::move(p_binding)); @@ -689,10 +674,11 @@ namespace sol { namespace u_detail { void* derived_this = static_cast(static_cast*>(this)); index_call_storage ics; ics.binding_data = b.data(); - ics.index = is_index || is_static_index ? &Binding::template call_with_ : &Binding::template index_call_with_; - ics.new_index - = is_new_index || is_static_new_index ? &Binding::template call_with_ : &Binding::template index_call_with_; - + ics.index = is_index || is_static_index ? &Binding::template call_with_ + : &Binding::template index_call_with_; + ics.new_index = is_new_index || is_static_new_index ? &Binding::template call_with_ + : &Binding::template index_call_with_; + string_for_each_metatable_func for_each_fx; for_each_fx.is_destruction = is_destruction; for_each_fx.is_index = is_index; @@ -704,7 +690,7 @@ namespace sol { namespace u_detail { for_each_fx.p_ics = &ics; if constexpr (is_lua_c_function_v) { for_each_fx.is_unqualified_lua_CFunction = true; - for_each_fx.call_func = *static_cast(ics.binding_data); + for_each_fx.call_func = *static_cast(ics.binding_data); } else if constexpr (is_lua_reference_or_proxy_v) { for_each_fx.is_unqualified_lua_reference = true; diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index 64203a9a..9388e17b 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/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: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 diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index 3bb98b60..5b479a5b 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.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 - inline decltype(auto) deref_non_pointer(T&& item) { + inline decltype(auto) deref_move_only(T&& item) { using Tu = meta::unqualified_t; - if constexpr (meta::is_pointer_like_v && !std::is_pointer_v) { + if constexpr (meta::is_pointer_like_v && !std::is_pointer_v && !std::is_copy_constructible_v) { return *std::forward(item); } else { @@ -8266,6 +8266,8 @@ namespace sol { // beginning of sol/error_handler.hpp +#include + 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(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(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(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::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(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 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 struct argument_handler> { - 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(); - addendum += "("; - int marker = 0; - (void)detail::swallow{int(), (detail::accumulate_and_mark(detail::demangle(), addendum, marker), int())...}; - addendum += ")')"; - return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + 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(); + aux_message += "("; + int marker = 0; + (void)detail::swallow{ int(), (detail::accumulate_and_mark(detail::demangle(), 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 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...>::value) { + if constexpr (!traits::runtime_variadics_t::value + && meta::find_in_pack_v, meta::index_value...>::value) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), @@ -16255,25 +16261,25 @@ namespace sol { if constexpr (!traits::runtime_variadics_t::value) { if (traits::free_arity != fxarity) { return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } } stack::record tracking{}; if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } return matchfx(types(), meta::index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } @@ -16331,7 +16337,8 @@ namespace sol { typedef meta::tuple_types 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...>::value) { + if constexpr (!traits::runtime_variadics_t::value + && meta::find_in_pack_v, meta::index_value...>::value) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), @@ -16345,25 +16352,25 @@ namespace sol { if constexpr (!traits::runtime_variadics_t::value) { if (traits::free_arity != fxarity) { return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } } stack::record tracking{}; if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { - return overload_match_arity(types(), - std::index_sequence(), - std::index_sequence(), - std::forward(matchfx), - L, - fxarity, - start, - std::forward(args)...); + return overload_match_arity(types(), + std::index_sequence(), + std::index_sequence(), + std::forward(matchfx), + L, + fxarity, + start, + std::forward(args)...); } return matchfx(types(), meta::index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } @@ -16424,7 +16431,7 @@ namespace sol { template static int call(lua_State* L, Fx&& f, Args&&... args) { - if constexpr(is_lua_reference_v>) { + if constexpr (is_lua_reference_v>) { if constexpr (is_index) { return stack::push(L, std::forward(f), std::forward(args)...); } @@ -16467,6 +16474,7 @@ namespace sol { } else { if constexpr (std::is_const_v>) { + (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( - returns_list(), types<>(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), std::forward(args)...); + return stack::call_into_lua(returns_list(), + types<>(), + L, + boost + (is_variable ? 3 : 2), + caller(), + std::forward(fx), + std::forward(args)...); } } else { @@ -16622,16 +16635,16 @@ namespace sol { using caller = typename wrap::caller; if constexpr (sizeof...(Args) > 0) { return stack::call_into_lua(types(), - args_list(), - L, - boost + (is_variable ? 3 : 2), - caller(), - std::forward(fx), - std::forward(args)...); + args_list(), + L, + boost + (is_variable ? 3 : 2), + caller(), + std::forward(fx), + std::forward(args)...); } else { using Ta = meta::conditional_t, object_type, T>; - #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE +#if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE auto maybeo = stack::check_get(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { @@ -16641,12 +16654,12 @@ namespace sol { } object_type* po = static_cast(maybeo.value()); object_type& o = *po; - #else +#else object_type& o = static_cast(*stack::get>(L, 1)); - #endif // Safety +#endif // Safety return stack::call_into_lua( - types(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), o); + types(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), o); } } } @@ -16821,8 +16834,7 @@ namespace sol { template static int call(lua_State* L, F&& f, Args&&... args) { - constexpr bool is_specialized = meta::any< - std::is_same, + constexpr bool is_specialized = meta::any, meta::is_specialization_of, meta::is_specialization_of, meta::is_specialization_of, @@ -16841,7 +16853,7 @@ namespace sol { } else { constexpr bool non_class_object_type = meta::any, - meta::boolean>::value != type::userdata>>::value; + meta::boolean>::value != type::userdata>>::value; if constexpr (non_class_object_type) { // The type being void means we don't have any arguments, so it might be a free functions? using args_list = typename traits_type::free_args_list; @@ -16955,7 +16967,8 @@ namespace sol { } } - template + template inline int call_user(lua_State* L) { auto& fx = stack::unqualified_get>(L, upvalue_index(start)); return call_wrapped(L, fx); @@ -19522,7 +19535,7 @@ namespace sol { captured_type; typedef typename meta::iterator_tag::type iterator_category; typedef std::is_same is_input_iterator; - typedef meta::conditional_t()))> push_type; + typedef meta::conditional_t()))> push_type; typedef std::is_copy_assignable is_copyable; typedef meta::neg, std::is_const>, meta::neg>> is_writable; typedef meta::unqualified_t>()))> key_type; @@ -19595,12 +19608,12 @@ namespace sol { template static detail::error_result get_associative(std::true_type, lua_State* L, Iter& it) { decltype(auto) v = *it; - return stack::stack_detail::push_reference(L, detail::deref_non_pointer(v.second)); + return stack::stack_detail::push_reference(L, detail::deref_move_only(v.second)); } template static detail::error_result get_associative(std::false_type, lua_State* L, Iter& it) { - return stack::stack_detail::push_reference(L, detail::deref_non_pointer(*it)); + return stack::stack_detail::push_reference(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(L, detail::deref_non_pointer(it->second)); + p += stack::stack_detail::push_reference(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(L, detail::deref_non_pointer(*it)); + p += stack::stack_detail::push_reference(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::extent::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,17 +21267,14 @@ 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) { std::string& key = *p_key; usertype_storage_base& usb = *p_usb; index_call_storage& ics = *p_ics; - + if (smt == submetatable_type::named) { // do not override __call or // other specific meta functions on named metatable: @@ -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(base_class_check_func), t.stack_index()); stack::set_field(L, detail::base_class_cast_key(), reinterpret_cast(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& ptr) const { return binding_data == ptr->data(); @@ -21525,7 +21522,7 @@ namespace sol { namespace u_detail { type_table = lua_nil; gc_names_table = lua_nil; named_metatable = lua_nil; - + storage.clear(); string_keys.clear(); auxiliary_keys.clear(); @@ -21545,7 +21542,7 @@ namespace sol { namespace u_detail { #else optional&> maybe_base_storage = maybe_get_usertype_storage(L); if (static_cast(maybe_base_storage)) { - base_result = self_index_call(bases(), L, *maybe_base_storage); + base_result = self_index_call(bases(), L, *maybe_base_storage); keep_going = base_result == base_walking_failed_index; } #endif // Fast versus slow, safe base lookup @@ -21583,7 +21580,7 @@ namespace sol { namespace u_detail { } } if (target != nullptr) { - if constexpr(is_new_index) { + if constexpr (is_new_index) { // set value and return *target = reference(L, 3); return 0; @@ -21712,7 +21709,7 @@ namespace sol { namespace u_detail { }; template - inline int destruct_usertype_storage (lua_State* L) { + inline int destruct_usertype_storage(lua_State* L) { return detail::user_alloc_destruct>(L); } @@ -21723,6 +21720,7 @@ namespace sol { namespace u_detail { using Binding = binding; using is_var_bind = is_variable_binding; if constexpr (std::is_same_v) { + (void)key; std::unique_ptr p_binding = std::make_unique(std::forward(value)); Binding& b = *p_binding; this->storage.push_back(std::move(p_binding)); @@ -21768,10 +21766,11 @@ namespace sol { namespace u_detail { void* derived_this = static_cast(static_cast*>(this)); index_call_storage ics; ics.binding_data = b.data(); - ics.index = is_index || is_static_index ? &Binding::template call_with_ : &Binding::template index_call_with_; - ics.new_index - = is_new_index || is_static_new_index ? &Binding::template call_with_ : &Binding::template index_call_with_; - + ics.index = is_index || is_static_index ? &Binding::template call_with_ + : &Binding::template index_call_with_; + ics.new_index = is_new_index || is_static_new_index ? &Binding::template call_with_ + : &Binding::template index_call_with_; + string_for_each_metatable_func for_each_fx; for_each_fx.is_destruction = is_destruction; for_each_fx.is_index = is_index; @@ -21783,7 +21782,7 @@ namespace sol { namespace u_detail { for_each_fx.p_ics = &ics; if constexpr (is_lua_c_function_v) { for_each_fx.is_unqualified_lua_CFunction = true; - for_each_fx.call_func = *static_cast(ics.binding_data); + for_each_fx.call_func = *static_cast(ics.binding_data); } else if constexpr (is_lua_reference_or_proxy_v) { for_each_fx.is_unqualified_lua_reference = true; diff --git a/tests/runtime_tests/source/container.usertype_check.cpp b/tests/runtime_tests/source/container.usertype_check.cpp new file mode 100644 index 00000000..c798425f --- /dev/null +++ b/tests/runtime_tests/source/container.usertype_check.cpp @@ -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 + + +struct user_container_type : public std::vector { + typedef std::vector 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 err0 = lua.safe_script("a = {}"); + REQUIRE_FALSE(err0.has_value()); + + sol::object a = lua["a"]; + REQUIRE(a.is()); + REQUIRE_FALSE(a.is()); + REQUIRE_FALSE(a.is()); + REQUIRE_FALSE(a.is()); + REQUIRE_FALSE(a.is()); +} diff --git a/tests/runtime_tests/source/usertypes.unique.cpp b/tests/runtime_tests/source/usertypes.unique.cpp index e3028ea8..2399a2be 100644 --- a/tests/runtime_tests/source/usertypes.unique.cpp +++ b/tests/runtime_tests/source/usertypes.unique.cpp @@ -27,6 +27,17 @@ #include +struct unique_user_Display { + int value = 5; +}; + +std::vector> unique_user_foo() { + return { std::make_shared(), std::make_shared(), std::make_shared() }; +} + +int unique_user_bar(std::shared_ptr item) { + return item->value; +} struct factory_test { private: @@ -161,7 +172,7 @@ TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't ge TEST_CASE("usertype/unique void pointers", "can compile shared_ptr types and not trip the compiler or sol3's internals") { sol::state lua; - lua.set_function("f", [](std::shared_ptr d) { + lua.set_function("f", [](std::shared_ptr d) { int* pi = static_cast(d.get()); REQUIRE(*pi == 567); }); @@ -171,3 +182,15 @@ TEST_CASE("usertype/unique void pointers", "can compile shared_ptr 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 err0 = lua.safe_script("v3 = foo()"); + REQUIRE_FALSE(err0.has_value()); + sol::optional err1 = lua.safe_script("assert(bar(v3[1]) == 5)"); + REQUIRE_FALSE(err1.has_value()); +}