From ca46ef4d256c727a116366334b705ecda0a06c5d Mon Sep 17 00:00:00 2001
From: David Snopek <dsnopek@gmail.com>
Date: Wed, 24 Apr 2024 14:26:06 -0500
Subject: [PATCH] Give compile-time error if registering a class without its
 own `_bind_methods()` function

---
 include/godot_cpp/classes/wrapped.hpp |  5 +++++
 include/godot_cpp/core/class_db.hpp   |  1 +
 include/godot_cpp/core/type_info.hpp  | 10 ++++++++++
 3 files changed, 16 insertions(+)

diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp
index 97f9a6ed7..ce8c96815 100644
--- a/include/godot_cpp/classes/wrapped.hpp
+++ b/include/godot_cpp/classes/wrapped.hpp
@@ -214,6 +214,7 @@ protected:
                                                                                                                                                                                        \
 public:                                                                                                                                                                                \
 	typedef m_class self_type;                                                                                                                                                         \
+	typedef m_inherits parent_type;                                                                                                                                                    \
                                                                                                                                                                                        \
 	static void initialize_class() {                                                                                                                                                   \
 		static bool initialized = false;                                                                                                                                               \
@@ -381,6 +382,7 @@ public:
 private:                                                                                                                                                                               \
 	inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper;                                                                           \
 	void operator=(const m_class &p_rval) {}                                                                                                                                           \
+	friend class ::godot::ClassDB;                                                                                                                                                     \
                                                                                                                                                                                        \
 protected:                                                                                                                                                                             \
 	virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override {                                                                                      \
@@ -390,6 +392,8 @@ protected:
 	m_class(const char *p_godot_class) : m_inherits(p_godot_class) {}                                                                                                                  \
 	m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {}                                                                                                               \
                                                                                                                                                                                        \
+	static void _bind_methods() {}                                                                                                                                                     \
+                                                                                                                                                                                       \
 	static void (*_get_bind_methods())() {                                                                                                                                             \
 		return nullptr;                                                                                                                                                                \
 	}                                                                                                                                                                                  \
@@ -432,6 +436,7 @@ protected:
                                                                                                                                                                                        \
 public:                                                                                                                                                                                \
 	typedef m_class self_type;                                                                                                                                                         \
+	typedef m_inherits parent_type;                                                                                                                                                    \
                                                                                                                                                                                        \
 	static void initialize_class() {}                                                                                                                                                  \
                                                                                                                                                                                        \
diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp
index 6dedc1257..98e9f72c3 100644
--- a/include/godot_cpp/core/class_db.hpp
+++ b/include/godot_cpp/core/class_db.hpp
@@ -203,6 +203,7 @@ class ClassDB {
 template <typename T, bool is_abstract>
 void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
 	static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
+	static_assert(!FunctionsAreSame<T::self_type::_bind_methods, T::parent_type::_bind_methods>::value, "Class must declare 'static void _bind_methods'.");
 	static_assert(!std::is_abstract_v<T> || is_abstract, "Class is abstract, please use GDREGISTER_ABSTRACT_CLASS.");
 	instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
 
diff --git a/include/godot_cpp/core/type_info.hpp b/include/godot_cpp/core/type_info.hpp
index 589665157..096e0ecb8 100644
--- a/include/godot_cpp/core/type_info.hpp
+++ b/include/godot_cpp/core/type_info.hpp
@@ -58,6 +58,16 @@ struct TypesAreSame<A, A> {
 	static bool const value = true;
 };
 
+template <auto A, auto B>
+struct FunctionsAreSame {
+	static bool const value = false;
+};
+
+template <auto A>
+struct FunctionsAreSame<A, A> {
+	static bool const value = true;
+};
+
 template <typename B, typename D>
 struct TypeInherits {
 	static D *get_d();
