diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py index 3df26e3b73f..2974346a46f 100644 --- a/core/object/make_virtuals.py +++ b/core/object/make_virtuals.py @@ -127,7 +127,7 @@ def generate_version(argcount, const=False, returns=False, required=False): callptrargsptr += ", " argtext += f"m_type{i + 1}" callargtext += f"m_type{i + 1} arg{i + 1}" - callsiargs += f"Variant(arg{i + 1})" + callsiargs += f"_to_variant(arg{i + 1})" callsiargptrs += f"&vargs[{i}]" callptrargs += ( f"PtrToArg::EncodeT argval{i + 1} = (PtrToArg::EncodeT)arg{i + 1};\\\n" @@ -185,6 +185,8 @@ def run(target, source, env): #include "core/object/script_instance.h" +#include + #ifdef TOOLS_ENABLED #define GDVIRTUAL_TRACK(m_virtual, m_initialized)\\ if (_get_extension()->reloadable) {\\ @@ -198,6 +200,37 @@ def run(target, source, env): #define GDVIRTUAL_TRACK(m_virtual, m_initialized) #endif +// MSVC WORKAROUND START +// FIXME The below helper functions are needed to work around an MSVC bug. +// They should be removed (by modifying core/object/make_virtuals.py) once the bug ceases to be triggered. +// The bug is triggered by the following code: +// `Variant(arg)` +// Through the introduction of the move constructor, MSVC forgets that `operator Variant()` +// is also a valid way to resolve this call. So for some argument types, it fails the call because +// it cannot convert to `Variant`. +// The function `_to_variant` helps the compiler select `.operator Variant()` for appropriate arguments using SFINAE. + +template +struct has_variant_operator : std::false_type {}; + +template +struct has_variant_operator().operator Variant())>> : std::true_type {}; + +// Function that is enabled if T has `.operator Variant()`. +template +_ALWAYS_INLINE_ typename std::enable_if::value, Variant>::type +_to_variant(T&& t) { + return std::forward(t).operator Variant(); +} + +// Function that is enabled if T does not have `.operator Variant()`. +template +_ALWAYS_INLINE_ typename std::enable_if::value, Variant>::type +_to_variant(T&& t) { + return Variant(std::forward(t)); +} +// MSVC WORKAROUND END + """ for i in range(max_versions + 1): diff --git a/core/variant/variant.h b/core/variant/variant.h index 12528ae5155..736e03264b2 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -811,11 +811,25 @@ public: static void construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct = nullptr, void *p_construct_ud = nullptr); void operator=(const Variant &p_variant); // only this is enough for all the other types + void operator=(Variant &&p_variant) { + if (unlikely(this == &p_variant)) { + return; + } + clear(); + type = p_variant.type; + _data = p_variant._data; + p_variant.type = NIL; + } static void register_types(); static void unregister_types(); Variant(const Variant &p_variant); + Variant(Variant &&p_variant) { + type = p_variant.type; + _data = p_variant._data; + p_variant.type = NIL; + } _FORCE_INLINE_ Variant() {} _FORCE_INLINE_ ~Variant() { clear();