Fix up inheritance with special metamethods

- Inheritance was causing __index and __new_index to be overriden on the named metatables
- This meant special constructors and other metamethods might not have been set properly
- Use lua_rawset to directly slam dunk the value into the table
This commit is contained in:
ThePhD 2020-12-18 10:04:46 -05:00
parent 9c4e2d1094
commit 220335d95c
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
6 changed files with 83 additions and 26 deletions

View File

@ -1136,7 +1136,7 @@ namespace sol {
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>>;
meta::is_specialization_of<T, yielding_t>>;
template <typename T>
inline constexpr bool is_msvc_callable_rigged_v = is_msvc_callable_rigged<T>::value;

View File

@ -647,11 +647,13 @@ namespace sol { namespace u_detail {
this->named_index_table.push();
absolute_index metametatable_index(L, -1);
std::string_view call_metamethod_name = to_string(meta_function::call);
lua_pushlstring(L, call_metamethod_name.data(), call_metamethod_name.size());
stack::push(L, nullptr);
stack::push(L, b.data());
lua_CFunction target_func = &b.template call<false, false>;
lua_pushcclosure(L, target_func, 2);
lua_setfield(L, metametatable_index, to_string(meta_function::call).c_str());
lua_rawset(L, metametatable_index);
this->named_index_table.pop();
}
else if constexpr (std::is_same_v<KeyU, base_classes_tag>) {

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-18 04:17:10.718684 UTC
// This header was generated with sol v3.2.3 (revision 561c90ab)
// Generated 2020-12-18 15:03:36.644037 UTC
// This header was generated with sol v3.2.3 (revision 9c4e2d10)
// 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-18 04:17:10.578992 UTC
// This header was generated with sol v3.2.3 (revision 561c90ab)
// Generated 2020-12-18 15:03:36.620043 UTC
// This header was generated with sol v3.2.3 (revision 9c4e2d10)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_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-18 04:17:09.361797 UTC
// This header was generated with sol v3.2.3 (revision 561c90ab)
// Generated 2020-12-18 15:03:35.924132 UTC
// This header was generated with sol v3.2.3 (revision 9c4e2d10)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -7803,7 +7803,7 @@ namespace sol {
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>>;
meta::is_specialization_of<T, yielding_t>>;
template <typename T>
inline constexpr bool is_msvc_callable_rigged_v = is_msvc_callable_rigged<T>::value;
@ -22583,11 +22583,13 @@ namespace sol { namespace u_detail {
this->named_index_table.push();
absolute_index metametatable_index(L, -1);
std::string_view call_metamethod_name = to_string(meta_function::call);
lua_pushlstring(L, call_metamethod_name.data(), call_metamethod_name.size());
stack::push(L, nullptr);
stack::push(L, b.data());
lua_CFunction target_func = &b.template call<false, false>;
lua_pushcclosure(L, target_func, 2);
lua_setfield(L, metametatable_index, to_string(meta_function::call).c_str());
lua_rawset(L, metametatable_index);
this->named_index_table.pop();
}
else if constexpr (std::is_same_v<KeyU, base_classes_tag>) {

View File

@ -29,6 +29,7 @@
#include <iostream>
inline namespace sol2_test_usertypes_inheritance {
struct inh_test_A {
int a = 5;
};
@ -49,6 +50,24 @@ struct inh_test_D : inh_test_C {
}
};
class A {
public:
void hello() { std::cout << "This is class A" << std::endl; }
virtual void vhello() { std::cout << "A::vhello" << std::endl; }
virtual ~A() {}
public:
int a = 1;
};
class B : public A {
public:
virtual void vhello() override { std::cout << "B::vhello" << std::endl; }
virtual ~B() override {}
public:
int b = 2;
};
}
SOL_BASE_CLASSES(inh_test_D, inh_test_C);
SOL_BASE_CLASSES(inh_test_C, inh_test_B, inh_test_A);
SOL_DERIVED_CLASSES(inh_test_C, inh_test_D);
@ -113,3 +132,37 @@ TEST_CASE("inheritance/usertype derived non-hiding", "usertype classes must play
REQUIRE((lua.get<int>("dgn10") == 70));
REQUIRE((lua.get<int>("dgn") == 7));
}
TEST_CASE("inheritance/usertype metatable interference", "usertypes with overriden index/new_index methods (from e.g. base classes) were intercepting calls to the named metatable") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::coroutine, sol::lib::string, sol::lib::os, sol::lib::math, sol::lib::table, sol::lib::io, sol::lib::debug);
sol::usertype<A> uta = lua.new_usertype<A>("A", sol::base_classes, sol::base_list<>());
uta.set(sol::call_constructor, sol::constructors<A()>());
uta.set("a", &A::a);
uta.set("hello", &A::hello);
uta.set("vhello", &A::vhello);
sol::usertype<B> utb = lua.new_usertype<B>("B", sol::base_classes, sol::base_list<A>());
utb.set(sol::call_constructor, sol::constructors<B()>());
utb.set("b", &B::b);
utb.set("vhello", &B::vhello);
sol::optional<sol::error> maybe_error0 = lua.safe_script(R"(
local aa = A()
aa:hello()
)", sol::script_pass_on_error);
REQUIRE_FALSE(maybe_error0.has_value());
sol::optional<sol::error> maybe_error1 = lua.safe_script(R"(
local bb0 = B.new()
bb0:hello()
)", sol::script_pass_on_error);
REQUIRE_FALSE(maybe_error1.has_value());
sol::optional<sol::error> maybe_error2 = lua.safe_script(R"(
local bb1 = B()
bb1:hello()
)", sol::script_pass_on_error);
REQUIRE_FALSE(maybe_error2.has_value());
}