diff --git a/godot-macros/src/class/godot_api.rs b/godot-macros/src/class/godot_api.rs index de98a8188..cbf58a224 100644 --- a/godot-macros/src/class/godot_api.rs +++ b/godot-macros/src/class/godot_api.rs @@ -73,6 +73,12 @@ struct SignalDefinition { attributes: Vec, } +/// Holds information known from a constant's definition +struct ConstantDefinition { + constant: Constant, + attributes: Vec, +} + /// Codegen for `#[godot_api] impl MyType` fn transform_inherent_impl(mut decl: Impl) -> Result { let class_name = util::validate_impl(&decl, None, "godot_api")?; @@ -129,16 +135,27 @@ fn transform_inherent_impl(mut decl: Impl) -> Result { .map(|func_def| make_method_registration(&class_name, func_def)); let consts = process_godot_constants(&mut decl)?; + let mut integer_constant_cfg_attrs = Vec::new(); let mut integer_constant_names = Vec::new(); let mut integer_constant_values = Vec::new(); - for constant in consts.iter() { + for constant_def in consts.iter() { + let ConstantDefinition { + constant, + attributes, + } = constant_def; if constant.initializer.is_none() { return bail!(constant, "exported const should have initializer"); }; let name = &constant.name; + let cfg_attrs = util::extract_cfg_attrs(attributes) + .into_iter() + .collect::>(); + // Transport #[cfg] attrs to the FFI glue to ensure constants which were conditionally + // removed from compilation don't cause errors. + integer_constant_cfg_attrs.push(cfg_attrs); integer_constant_names.push(constant.name.to_string()); integer_constant_values.push(quote! { #class_name::#name }); } @@ -150,6 +167,7 @@ fn transform_inherent_impl(mut decl: Impl) -> Result { use ::godot::builtin::StringName; #( + #(#integer_constant_cfg_attrs)* ExportConstant::new( #class_name_obj, ConstantKind::Integer( @@ -307,8 +325,8 @@ fn process_godot_fns( Ok((func_definitions, signal_definitions)) } -fn process_godot_constants(decl: &mut Impl) -> Result, Error> { - let mut constant_signatures = vec![]; +fn process_godot_constants(decl: &mut Impl) -> Result, Error> { + let mut constant_definitions = vec![]; for item in decl.body_items.iter_mut() { let ImplMember::Constant(constant) = item else { @@ -316,6 +334,7 @@ fn process_godot_constants(decl: &mut Impl) -> Result, Error> { }; if let Some(attr) = extract_attributes(&constant, &constant.attributes)? { + let attributes = constant.attributes.clone(); // Remaining code no longer has attribute -- rest stays constant.attributes.remove(attr.index); @@ -330,13 +349,16 @@ fn process_godot_constants(decl: &mut Impl) -> Result, Error> { if constant.initializer.is_none() { return bail!(constant, "exported constant must have initializer"); } - constant_signatures.push(constant.clone()); + constant_definitions.push(ConstantDefinition { + constant: constant.clone(), + attributes, + }); } } } } - Ok(constant_signatures) + Ok(constant_definitions) } fn extract_attributes( diff --git a/itest/rust/src/register_tests/constant_test.rs b/itest/rust/src/register_tests/constant_test.rs index c671de9c4..558a9e653 100644 --- a/itest/rust/src/register_tests/constant_test.rs +++ b/itest/rust/src/register_tests/constant_test.rs @@ -40,6 +40,25 @@ impl HasConstants { #[constant] #[cfg(all())] const CONSTANT_RECOGNIZED_WITH_SIMPLE_PATH_ATTRIBUTE_BELOW_CONST_ATTR: bool = true; + + #[constant] + const CFG_REMOVES_CONSTANT: bool = true; + + #[cfg(any())] + #[constant] + const CFG_REMOVES_CONSTANT: bool = false; + + #[constant] + #[cfg(any())] + const CFG_REMOVES_CONSTANT: bool = false; + + #[cfg(any())] + #[constant] + const CFG_REMOVES_CONSTANT_FFI_GLUE: bool = true; + + #[constant] + #[cfg(any())] + const CFG_REMOVES_CONSTANT_FFI_GLUE: bool = true; } #[itest]