From 40b57bd87cb2edc23706610647e23c32fa1a1074 Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Wed, 22 Oct 2025 13:58:32 +0200 Subject: [PATCH 1/2] Deprecate #[class(no_init)] for editor plugins The Godot editor requires default-constructible plugins. Using `no_init` will cause an error when opened in the editor. --- godot-core/src/deprecated.rs | 6 ++++++ godot-macros/src/class/derive_godot_class.rs | 9 ++++++++- itest/rust/src/object_tests/virtual_methods_test.rs | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/godot-core/src/deprecated.rs b/godot-core/src/deprecated.rs index bde072132..00c88f4f8 100644 --- a/godot-core/src/deprecated.rs +++ b/godot-core/src/deprecated.rs @@ -37,6 +37,12 @@ pub use crate::emit_deprecated_warning; // ---------------------------------------------------------------------------------------------------------------------------------------------- // Library-side deprecations -- see usage description above. +#[deprecated = "\n\ + #[class(no_init, base=EditorPlugin)] will crash when opened in the editor.\n\ + EditorPlugin classes are automatically instantiated by Godot and require a default constructor.\n\ + Use #[class(init)] instead, or provide a custom init() function in the IEditorPlugin impl."] +pub const fn class_no_init_editor_plugin() {} + // ---------------------------------------------------------------------------------------------------------------------------------------------- // Godot-side deprecations (we may mark them deprecated but keep support). diff --git a/godot-macros/src/class/derive_godot_class.rs b/godot-macros/src/class/derive_godot_class.rs index e2b6533b4..cfea9ab46 100644 --- a/godot-macros/src/class/derive_godot_class.rs +++ b/godot-macros/src/class/derive_godot_class.rs @@ -290,7 +290,7 @@ pub fn make_existence_check(ident: &Ident) -> TokenStream { // ---------------------------------------------------------------------------------------------------------------------------------------------- // Implementation -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq)] enum InitStrategy { Generated, UserDefined, @@ -568,6 +568,13 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult. From ae6885b1ab594dc2f0493e3811041edd62c88277 Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Wed, 22 Oct 2025 14:07:10 +0200 Subject: [PATCH 2/2] Remove old attribute keys, but keep error message for now Concerns: - #[class(editor_plugin)] - #[class(hidden)] - #[init(default = ...)] Those already caused compile errors, since the deprecation functions no longer existed, so this is not a breaking change. However, the new approach produces more readable errors. --- godot-macros/src/class/derive_godot_class.rs | 48 ++++++++------------ 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/godot-macros/src/class/derive_godot_class.rs b/godot-macros/src/class/derive_godot_class.rs index cfea9ab46..b1696db12 100644 --- a/godot-macros/src/class/derive_godot_class.rs +++ b/godot-macros/src/class/derive_godot_class.rs @@ -531,11 +531,12 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult - ::godot::__deprecated::emit_deprecated_warning!(class_editor_plugin); - }); + // Removed #[class(editor_plugin)] + if let Some(key) = parser.handle_alone_with_span("editor_plugin")? { + return bail!( + key, + "#[class(editor_plugin)] has been removed in favor of #[class(tool, base=EditorPlugin)]", + ); } // #[class(rename = NewName)] @@ -556,20 +557,19 @@ fn parse_struct_attributes(class: &venial::Struct) -> ParseResult - ::godot::__deprecated::emit_deprecated_warning!(class_hidden); - }); + // Removed #[class(hidden)] + if let Some(key) = parser.handle_alone_with_span("hidden")? { + return bail!( + key, + "#[class(hidden)] has been renamed to #[class(internal)]", + ); } parser.finish()?; } // Deprecated: #[class(no_init)] with base=EditorPlugin - if init_strategy == InitStrategy::Absent && base_ty == "EditorPlugin" { + if matches!(init_strategy, InitStrategy::Absent) && base_ty == ident("EditorPlugin") { deprecations.push(quote! { ::godot::__deprecated::emit_deprecated_warning!(class_no_init_editor_plugin); }); @@ -594,6 +594,7 @@ fn parse_fields( ) -> ParseResult { let mut all_fields = vec![]; let mut base_field = Option::::None; + #[allow(unused_mut)] // Less chore when adding/removing deprecations. let mut deprecations = vec![]; let mut errors = vec![]; @@ -640,21 +641,12 @@ fn parse_fields( }); } - // Deprecated #[init(default = expr)] - if let Some((key, default)) = parser.handle_expr_with_key("default")? { - if field.default_val.is_some() { - return bail!( - key, - "Cannot use both `val` and `default` keys in #[init]; prefer using `val`" - ); - } - field.default_val = Some(FieldDefault { - default_val: default, - span: parser.span(), - }); - deprecations.push(quote_spanned! { parser.span()=> - ::godot::__deprecated::emit_deprecated_warning!(init_default); - }) + // Removed #[init(default = ...)] + if let Some((key, _default)) = parser.handle_expr_with_key("default")? { + return bail!( + key, + "#[init(default = ...)] has been renamed to #[init(val = ...)]", + ); } // #[init(node = "PATH")]