diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h
index 98c59eb67..481705345 100644
--- a/src/scripting/vm/vm.h
+++ b/src/scripting/vm/vm.h
@@ -561,13 +561,49 @@ struct FieldDesc
int BitValue;
};
+// Compile time validation of direct native functions
+struct DirectNativeDesc
+{
+ DirectNativeDesc() = default;
+
+ #define TP(n) typename P##n
+ #define VP(n) ValidateType
()
+ template DirectNativeDesc(Ret(*func)()) : Ptr(reinterpret_cast(func)) { ValidateType(); }
+ template DirectNativeDesc(Ret(*func)(P1)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); }
+ template DirectNativeDesc(Ret(*func)(P1,P2)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); }
+ template DirectNativeDesc(Ret(*func)(P1,P2,P3)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); }
+ template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); VP(4); }
+ template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); VP(4); VP(5); }
+ template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); }
+ template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); }
+ template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); }
+ template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); }
+ template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)) : Ptr(reinterpret_cast(func)) { ValidateType(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); }
+ #undef TP
+ #undef VP
+
+ template void ValidateType() { static_assert(is_valid::value, "Argument type is not valid as a direct native parameter or return type"); }
+
+ // Traits for the types we are interested in
+ template struct is_valid { static const bool value = false; };
+ template struct is_valid { static const bool value = true; };
+ template struct is_valid { static const bool value = true; };
+ template<> struct is_valid { static const bool value = true; };
+ template<> struct is_valid { static const bool value = true; };
+ template<> struct is_valid { static const bool value = true; };
+
+ operator void *() const { return Ptr; }
+
+ void *Ptr = nullptr;
+};
+
struct AFuncDesc
{
const char *ClassName;
const char *FuncName;
actionf_p Function;
VMNativeFunction **VMPointer;
- void *DirectNative;
+ DirectNativeDesc DirectNative;
};
#if defined(_MSC_VER)
@@ -591,16 +627,15 @@ struct AFuncDesc
#define DEFINE_ACTION_FUNCTION_NATIVE(cls, name, native) \
static int AF_##cls##_##name(VM_ARGS); \
VMNativeFunction *cls##_##name##_VMPtr; \
- static const AFuncDesc cls##_##name##_Hook = { #cls, #name, AF_##cls##_##name, &cls##_##name##_VMPtr, reinterpret_cast(native) }; \
+ static const AFuncDesc cls##_##name##_Hook = { #cls, #name, AF_##cls##_##name, &cls##_##name##_VMPtr, native }; \
extern AFuncDesc const *const cls##_##name##_HookPtr; \
MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \
static int AF_##cls##_##name(VM_ARGS)
-//#define DEFINE_ACTION_FUNCTION(cls, name) DEFINE_ACTION_FUNCTION_NATIVE(cls, name, nullptr)
#define DEFINE_ACTION_FUNCTION(cls, name) \
static int AF_##cls##_##name(VM_ARGS); \
VMNativeFunction *cls##_##name##_VMPtr; \
- static const AFuncDesc cls##_##name##_Hook = { #cls, #name, AF_##cls##_##name, &cls##_##name##_VMPtr, nullptr }; \
+ static const AFuncDesc cls##_##name##_Hook = { #cls, #name, AF_##cls##_##name, &cls##_##name##_VMPtr, {} }; \
extern AFuncDesc const *const cls##_##name##_HookPtr; \
MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \
static int AF_##cls##_##name(VM_ARGS)