Skip to content

Commit fc2d6f8

Browse files
committed
Allow #[cfg] to be used with #[func]
1 parent 3491d7b commit fc2d6f8

File tree

5 files changed

+55
-0
lines changed

5 files changed

+55
-0
lines changed

godot-macros/src/class/data_models/field_var.rs

+6
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ impl GetterSetterImpl {
194194
class_name,
195195
FuncDefinition {
196196
func: signature,
197+
// Since we're analyzing a struct's field, we don't have access to the corresponding get/set function's
198+
// external (non-#[func]) attributes. We have to assume the function exists and has the name the user
199+
// gave us, with the expected signature.
200+
// Ideally, we'd be able to place #[cfg_attr] on #[var(get)] and #[var(set)] to be able to match a
201+
// #[cfg()] (for instance) placed on the getter/setter function, but that is not currently supported.
202+
external_attributes: Vec::new(),
197203
rename: None,
198204
has_gd_self: false,
199205
},

godot-macros/src/class/data_models/func.rs

+9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use quote::{format_ident, quote};
1212
pub struct FuncDefinition {
1313
/// Raw information about the Rust function.
1414
pub func: venial::Function,
15+
/// The function's non-gdext attributes (that is, excluding #[func]).
16+
pub external_attributes: Vec<venial::Attribute>,
1517
/// The name the function will be exposed as in Godot. If `None`, the Rust function name is used.
1618
pub rename: Option<String>,
1719
pub has_gd_self: bool,
@@ -78,7 +80,14 @@ pub fn make_method_registration(
7880
};
7981
let param_ident_strs = param_idents.iter().map(|ident| ident.to_string());
8082

83+
// Transport #[cfg] attrs to the FFI glue to ensure functions which were conditionally
84+
// removed from compilation don't cause errors.
85+
let cfg_attrs = util::extract_cfg_attrs(&func_definition.external_attributes)
86+
.into_iter()
87+
.collect::<Vec<_>>();
88+
8189
quote! {
90+
#(#cfg_attrs)*
8291
{
8392
use ::godot::obj::GodotClass;
8493
use ::godot::builtin::meta::registration::method::MethodInfo;

godot-macros/src/class/godot_api.rs

+2
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ fn process_godot_fns(decl: &mut Impl) -> Result<(Vec<FuncDefinition>, Vec<Functi
238238
rename,
239239
has_gd_self,
240240
} => {
241+
let external_attributes = method.attributes.clone();
241242
// Signatures are the same thing without body
242243
let mut sig = util::reduce_to_signature(method);
243244
if *has_gd_self {
@@ -249,6 +250,7 @@ fn process_godot_fns(decl: &mut Impl) -> Result<(Vec<FuncDefinition>, Vec<Functi
249250
}
250251
func_definitions.push(FuncDefinition {
251252
func: sig,
253+
external_attributes,
252254
rename: rename.clone(),
253255
has_gd_self: *has_gd_self,
254256
});

godot-macros/src/util/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,15 @@ pub(crate) fn path_ends_with(path: &[TokenTree], expected: &str) -> bool {
227227
.unwrap_or(false)
228228
}
229229

230+
pub(crate) fn extract_cfg_attrs(
231+
attrs: &[venial::Attribute],
232+
) -> impl IntoIterator<Item = &venial::Attribute> {
233+
attrs.iter().filter(|attr| {
234+
attr.get_single_path_segment()
235+
.map_or(false, |name| name == "cfg")
236+
})
237+
}
238+
230239
pub(crate) struct DeclInfo {
231240
pub where_: Option<WhereClause>,
232241
pub generic_params: Option<GenericParamList>,

itest/rust/src/register_tests/func_test.rs

+29
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,35 @@ impl GdSelfReference {
8989
f1 && f2
9090
}
9191

92+
#[func]
93+
fn cfg_removes_function() -> bool {
94+
true
95+
}
96+
97+
#[cfg(any())]
98+
#[func]
99+
fn cfg_removes_function() -> bool {
100+
false
101+
}
102+
103+
#[func]
104+
#[cfg(any())]
105+
fn cfg_removes_function() -> bool {
106+
false
107+
}
108+
109+
#[cfg(any())]
110+
#[func]
111+
fn cfg_removes_function_ffi_glue() -> bool {
112+
true
113+
}
114+
115+
#[func]
116+
#[cfg(any())]
117+
fn cfg_removes_function_ffi_glue() -> bool {
118+
true
119+
}
120+
92121
#[signal]
93122
#[rustfmt::skip]
94123
fn signal_shouldnt_panic_with_segmented_path_attribute();

0 commit comments

Comments
 (0)