diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index c7b7dd1a2..d8eb9de7a 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -78,6 +78,12 @@ pub(crate) fn to_known_assoc_constant(associated_to: &Path, name: &str) -> Optio Some(format!("{}_{}", prefix, name)) } +#[derive(Debug, Clone)] +pub struct LiteralStructField { + pub value: Literal, + pub cfg: Option, +} + #[derive(Debug, Clone)] pub enum Literal { Expr(String), @@ -101,7 +107,7 @@ pub enum Literal { Struct { path: Path, export_name: String, - fields: HashMap, + fields: HashMap, }, Cast { ty: Type, @@ -135,7 +141,7 @@ impl Literal { self_ty.name().clone_into(export_name); } for ref mut expr in fields.values_mut() { - expr.replace_self_with(self_ty); + expr.value.replace_self_with(self_ty); } } Literal::Cast { @@ -203,7 +209,7 @@ impl Literal { Literal::FieldAccess { ref base, .. } => base.visit(visitor), Literal::Struct { ref fields, .. } => { for (_name, field) in fields.iter() { - if !field.visit(visitor) { + if !field.value.visit(visitor) { return false; } } @@ -250,7 +256,7 @@ impl Literal { } => { config.export.rename(export_name); for lit in fields.values_mut() { - lit.rename_for_config(config); + lit.value.rename_for_config(config); } } Literal::FieldAccess { ref mut base, .. } => { @@ -388,12 +394,13 @@ impl Literal { } => name, _ => return Err(format!("Unsupported call expression. {:?}", *expr)), }; - let mut fields = HashMap::::default(); + let mut fields = HashMap::::default(); for (index, arg) in args.iter().enumerate() { let ident = member_to_ident(&syn::Member::Unnamed(syn::Index::from(index))).to_string(); let value = Literal::load(arg)?; - fields.insert(ident, value); + let field = LiteralStructField { value, cfg: None }; + fields.insert(ident, field); } Ok(Literal::Struct { path: Path::new(struct_name.clone()), @@ -408,11 +415,13 @@ impl Literal { .. }) => { let struct_name = path.segments[0].ident.unraw().to_string(); - let mut field_map = HashMap::::default(); + let mut field_map = HashMap::::default(); for field in fields { let ident = member_to_ident(&field.member).to_string(); + let cfg = Cfg::load(&field.attrs); let value = Literal::load(&field.expr)?; - field_map.insert(ident, value); + let field = LiteralStructField { value, cfg }; + field_map.insert(ident, field); } Ok(Literal::Struct { path: Path::new(struct_name.clone()), @@ -682,7 +691,7 @@ impl Constant { if !out.bindings().struct_is_transparent(path) { break; } - value = fields.iter().next().unwrap().1 + value = &fields.iter().next().unwrap().1.value } language_backend.write_documentation(out, self.documentation()); diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index b41a3c462..3968193ec 100644 --- a/src/bindgen/language_backend/clike.rs +++ b/src/bindgen/language_backend/clike.rs @@ -912,19 +912,19 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { let ordered_fields = out.bindings().struct_field_names(path); for (i, ordered_key) in ordered_fields.iter().enumerate() { if let Some(lit) = fields.get(ordered_key) { + let condition = lit.cfg.to_condition(self.config); if is_constexpr { out.new_line(); + condition.write_before(self.config, out); // TODO: Some C++ versions (c++20?) now support designated // initializers, consider generating them. write!(out, "/* .{} = */ ", ordered_key); - self.write_literal(out, lit); + self.write_literal(out, &lit.value); if i + 1 != ordered_fields.len() { write!(out, ","); - if !is_constexpr { - write!(out, " "); - } } + condition.write_after(self.config, out); } else { if i > 0 { write!(out, ", "); @@ -937,7 +937,7 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { } else { write!(out, ".{} = ", ordered_key); } - self.write_literal(out, lit); + self.write_literal(out, &lit.value); } } } diff --git a/src/bindgen/language_backend/cython.rs b/src/bindgen/language_backend/cython.rs index 8497f3cd0..0327ffd06 100644 --- a/src/bindgen/language_backend/cython.rs +++ b/src/bindgen/language_backend/cython.rs @@ -399,7 +399,7 @@ impl LanguageBackend for CythonLanguageBackend<'_> { } else { is_first_field = false; } - self.write_literal(out, lit); + self.write_literal(out, &lit.value); } } write!(out, " }}"); diff --git a/tests/expectations/cfg.c b/tests/expectations/cfg.c index 9285f300e..800b518f6 100644 --- a/tests/expectations/cfg.c +++ b/tests/expectations/cfg.c @@ -77,6 +77,8 @@ typedef struct { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ .field = 0 } +#define ConditionalField_ONE (ConditionalField){ .field = 1 } typedef struct { int32_t x; diff --git a/tests/expectations/cfg.compat.c b/tests/expectations/cfg.compat.c index 053c4052f..6a4574357 100644 --- a/tests/expectations/cfg.compat.c +++ b/tests/expectations/cfg.compat.c @@ -95,6 +95,8 @@ typedef struct { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ .field = 0 } +#define ConditionalField_ONE (ConditionalField){ .field = 1 } typedef struct { int32_t x; diff --git a/tests/expectations/cfg.cpp b/tests/expectations/cfg.cpp index d7b6250dd..1eed9afd2 100644 --- a/tests/expectations/cfg.cpp +++ b/tests/expectations/cfg.cpp @@ -201,6 +201,16 @@ struct ConditionalField { #endif ; }; +constexpr static const ConditionalField ConditionalField_ZERO = ConditionalField{ +#if defined(X11) + /* .field = */ 0 +#endif +}; +constexpr static const ConditionalField ConditionalField_ONE = ConditionalField{ +#if defined(X11) + /* .field = */ 1 +#endif +}; struct Normal { int32_t x; diff --git a/tests/expectations/cfg.pyx b/tests/expectations/cfg.pyx index e23fc7033..803fd7a79 100644 --- a/tests/expectations/cfg.pyx +++ b/tests/expectations/cfg.pyx @@ -57,6 +57,8 @@ cdef extern from *: ctypedef struct ConditionalField: int32_t field; + const ConditionalField ConditionalField_ZERO # = { 0 } + const ConditionalField ConditionalField_ONE # = { 1 } ctypedef struct Normal: int32_t x; diff --git a/tests/expectations/cfg_both.c b/tests/expectations/cfg_both.c index 510e34e8d..55fcc894b 100644 --- a/tests/expectations/cfg_both.c +++ b/tests/expectations/cfg_both.c @@ -77,6 +77,8 @@ typedef struct ConditionalField { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ .field = 0 } +#define ConditionalField_ONE (ConditionalField){ .field = 1 } typedef struct Normal { int32_t x; diff --git a/tests/expectations/cfg_both.compat.c b/tests/expectations/cfg_both.compat.c index 2377824e1..000b03d41 100644 --- a/tests/expectations/cfg_both.compat.c +++ b/tests/expectations/cfg_both.compat.c @@ -95,6 +95,8 @@ typedef struct ConditionalField { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ .field = 0 } +#define ConditionalField_ONE (ConditionalField){ .field = 1 } typedef struct Normal { int32_t x; diff --git a/tests/expectations/cfg_tag.c b/tests/expectations/cfg_tag.c index 8cc885383..f9cad7b5e 100644 --- a/tests/expectations/cfg_tag.c +++ b/tests/expectations/cfg_tag.c @@ -77,6 +77,8 @@ struct ConditionalField { #endif ; }; +#define ConditionalField_ZERO (ConditionalField){ .field = 0 } +#define ConditionalField_ONE (ConditionalField){ .field = 1 } struct Normal { int32_t x; diff --git a/tests/expectations/cfg_tag.compat.c b/tests/expectations/cfg_tag.compat.c index ec9763536..cfe66ffd3 100644 --- a/tests/expectations/cfg_tag.compat.c +++ b/tests/expectations/cfg_tag.compat.c @@ -95,6 +95,8 @@ struct ConditionalField { #endif ; }; +#define ConditionalField_ZERO (ConditionalField){ .field = 0 } +#define ConditionalField_ONE (ConditionalField){ .field = 1 } struct Normal { int32_t x; diff --git a/tests/expectations/cfg_tag.pyx b/tests/expectations/cfg_tag.pyx index e508bb30a..6a0d44d78 100644 --- a/tests/expectations/cfg_tag.pyx +++ b/tests/expectations/cfg_tag.pyx @@ -57,6 +57,8 @@ cdef extern from *: cdef struct ConditionalField: int32_t field; + const ConditionalField ConditionalField_ZERO # = { 0 } + const ConditionalField ConditionalField_ONE # = { 1 } cdef struct Normal: int32_t x; diff --git a/tests/rust/cfg.rs b/tests/rust/cfg.rs index 70893609f..0efe3546e 100644 --- a/tests/rust/cfg.rs +++ b/tests/rust/cfg.rs @@ -49,6 +49,17 @@ struct ConditionalField { field: i32, } +impl ConditionalField { + pub const ZERO: Self = Self { + #[cfg(x11)] + field: 0, + }; + pub const ONE: Self = Self { + #[cfg(x11)] + field: 1, + }; +} + #[cfg(all(unix, x11))] #[no_mangle] pub extern "C" fn root(a: FooHandle, c: C)