Skip to content

Commit 1b635d5

Browse files
committed
Allow #[cfg] to be used with #[constant]
1 parent 81fd6d0 commit 1b635d5

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

godot-macros/src/class/godot_api.rs

+11
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {
136136
.map(|func_def| make_method_registration(&class_name, func_def));
137137

138138
let consts = process_godot_constants(&mut decl)?;
139+
let mut integer_constant_cfg_attrs = Vec::new();
139140
let mut integer_constant_names = Vec::new();
140141
let mut integer_constant_values = Vec::new();
141142

@@ -146,6 +147,15 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {
146147

147148
let name = &constant.name;
148149

150+
// Unlike with #[func] and #[signal], we don't remove the attributes from Constant
151+
// signatures within 'process_godot_constants'.
152+
let cfg_attrs = util::extract_cfg_attrs(&constant.attributes)
153+
.into_iter()
154+
.collect::<Vec<_>>();
155+
156+
// Transport #[cfg] attrs to the FFI glue to ensure constants which were conditionally
157+
// removed from compilation don't cause errors.
158+
integer_constant_cfg_attrs.push(cfg_attrs);
149159
integer_constant_names.push(constant.name.to_string());
150160
integer_constant_values.push(quote! { #class_name::#name });
151161
}
@@ -157,6 +167,7 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {
157167
use ::godot::builtin::StringName;
158168

159169
#(
170+
#(#integer_constant_cfg_attrs)*
160171
ExportConstant::new(
161172
#class_name_obj,
162173
ConstantKind::Integer(

itest/rust/src/register_tests/constant_test.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,45 @@ impl HasConstants {
4040
#[constant]
4141
#[cfg(all())]
4242
const CONSTANT_RECOGNIZED_WITH_SIMPLE_PATH_ATTRIBUTE_BELOW_CONST_ATTR: bool = true;
43+
44+
// The three identically-named definitions below should be mutually exclusive thanks to #[cfg].
45+
#[constant]
46+
const CFG_REMOVES_DUPLICATE_CONSTANT_DEF: i64 = 5;
47+
48+
#[cfg(any())]
49+
#[constant]
50+
const CFG_REMOVES_DUPLICATE_CONSTANT_DEF: i64 = compile_error!("Removed by #[cfg]");
51+
52+
#[constant]
53+
#[cfg(any())]
54+
const CFG_REMOVES_DUPLICATE_CONSTANT_DEF: i64 = compile_error!("Removed by #[cfg]");
55+
56+
// The constant below should end up not being defined at all.
57+
#[cfg(any())]
58+
#[constant]
59+
const CFG_REMOVES_CONSTANT: bool = compile_error!("Removed by #[cfg]");
60+
61+
#[constant]
62+
#[cfg(any())]
63+
const CFG_REMOVES_CONSTANT: bool = compile_error!("Removed by #[cfg]");
64+
}
65+
66+
/// Checks at runtime if a class has a given integer constant through [ClassDb].
67+
fn class_has_integer_constant<T: GodotClass>(name: &str) -> bool {
68+
ClassDb::singleton().class_has_integer_constant(T::class_name().to_string_name(), name.into())
4369
}
4470

4571
#[itest]
4672
fn constants_correct_value() {
47-
const CONSTANTS: [(&str, i64); 4] = [
73+
const CONSTANTS: [(&str, i64); 5] = [
4874
("A", HasConstants::A),
4975
("B", HasConstants::B as i64),
5076
("C", HasConstants::C as i64),
5177
("D", HasConstants::D as i64),
78+
(
79+
"CFG_REMOVES_DUPLICATE_CONSTANT_DEF",
80+
HasConstants::CFG_REMOVES_DUPLICATE_CONSTANT_DEF,
81+
),
5282
];
5383

5484
let constants = ClassDb::singleton()
@@ -72,6 +102,16 @@ fn constants_correct_value() {
72102
static_assert!(HasConstants::CONSTANT_RECOGNIZED_WITH_SIMPLE_PATH_ATTRIBUTE_BELOW_CONST_ATTR);
73103
}
74104

105+
#[itest]
106+
fn cfg_removes_or_keeps_constants() {
107+
assert!(class_has_integer_constant::<HasConstants>(
108+
"CFG_REMOVES_DUPLICATE_CONSTANT_DEF"
109+
));
110+
assert!(!class_has_integer_constant::<HasConstants>(
111+
"CFG_REMOVES_CONSTANT"
112+
));
113+
}
114+
75115
#[derive(GodotClass)]
76116
struct HasOtherConstants {}
77117

0 commit comments

Comments
 (0)