From 22a4c6ff4efc7ce2309cebfe54a5e82e5a271093 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 11 Aug 2024 01:05:47 +0900 Subject: [PATCH] struct literal defines by condition --- src/bindgen/language_backend/clike.rs | 47 ++++++++++++++++++++++----- tests/expectations/cfg.c | 12 +++++++ tests/expectations/cfg.compat.c | 12 +++++++ tests/expectations/cfg.cpp | 6 ++++ tests/expectations/cfg.pyx | 2 ++ tests/expectations/cfg_both.c | 12 +++++++ tests/expectations/cfg_both.compat.c | 12 +++++++ tests/expectations/cfg_tag.c | 12 +++++++ tests/expectations/cfg_tag.compat.c | 12 +++++++ tests/expectations/cfg_tag.pyx | 2 ++ tests/rust/cfg.rs | 11 +++++++ 11 files changed, 131 insertions(+), 9 deletions(-) diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index 3830b02a..553354e8 100644 --- a/src/bindgen/language_backend/clike.rs +++ b/src/bindgen/language_backend/clike.rs @@ -902,6 +902,18 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { write!(out, "{}", export_name); } + macro_rules! write_field_name { + ($out:ident, $key:ident) => { + if self.config.language == Language::Cxx { + // TODO: Some C++ versions (c++20?) now support designated + // initializers, consider generating them. + write!($out, "/* .{} = */ ", $key); + } else { + write!($out, ".{} = ", $key); + } + }; + } + write!(out, "{{"); if is_constexpr { out.push_tab(); @@ -912,12 +924,11 @@ 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(); - // TODO: Some C++ versions (c++20?) now support designated - // initializers, consider generating them. - write!(out, "/* .{} = */ ", ordered_key); + write_field_name!(out, ordered_key); self.write_literal(out, &lit.value); if i + 1 != ordered_fields.len() { write!(out, ","); @@ -930,14 +941,14 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { write!(out, ", "); } - if self.config.language == Language::Cxx { - // TODO: Some C++ versions (c++20?) now support designated - // initializers, consider generating them. - write!(out, "/* .{} = */ ", ordered_key); + if condition.is_some() { + write!(out, "__{export_name}_{ordered_key}("); + self.write_literal(out, &lit.value); + write!(out, ")") } else { - write!(out, ".{} = ", ordered_key); + write_field_name!(out, ordered_key); + self.write_literal(out, &lit.value); } - self.write_literal(out, &lit.value); } } } @@ -948,6 +959,24 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { write!(out, " "); } write!(out, "}}"); + + if self.config.language == Language::C { + for ordered_key in ordered_fields.iter() { + if let Some(lit) = fields.get(ordered_key) { + if let Some(condition) = lit.cfg.to_condition(self.config) { + out.new_line(); + condition.write_before(self.config, out); + let define = format!("#define __{export_name}_{ordered_key}(v)"); + write!(out, "{define} "); + write_field_name!(out, ordered_key); + write!(out, "(v)"); + write!(out, "\n#else\n"); + write!(out, "{define}"); + condition.write_after(self.config, out); + } + } + } + } } } } diff --git a/tests/expectations/cfg.c b/tests/expectations/cfg.c index 9285f300..b4115096 100644 --- a/tests/expectations/cfg.c +++ b/tests/expectations/cfg.c @@ -77,6 +77,18 @@ typedef struct { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ __ConditionalField_field(0) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif +#define ConditionalField_ONE (ConditionalField){ __ConditionalField_field(1) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif typedef struct { int32_t x; diff --git a/tests/expectations/cfg.compat.c b/tests/expectations/cfg.compat.c index 053c4052..73d9f6ed 100644 --- a/tests/expectations/cfg.compat.c +++ b/tests/expectations/cfg.compat.c @@ -95,6 +95,18 @@ typedef struct { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ __ConditionalField_field(0) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif +#define ConditionalField_ONE (ConditionalField){ __ConditionalField_field(1) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif typedef struct { int32_t x; diff --git a/tests/expectations/cfg.cpp b/tests/expectations/cfg.cpp index d7b6250d..1cd0447a 100644 --- a/tests/expectations/cfg.cpp +++ b/tests/expectations/cfg.cpp @@ -201,6 +201,12 @@ struct ConditionalField { #endif ; }; +constexpr static const ConditionalField ConditionalField_ZERO = ConditionalField{ + /* .field = */ 0 +}; +constexpr static const ConditionalField ConditionalField_ONE = ConditionalField{ + /* .field = */ 1 +}; struct Normal { int32_t x; diff --git a/tests/expectations/cfg.pyx b/tests/expectations/cfg.pyx index e23fc703..803fd7a7 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 510e34e8..7d0d639c 100644 --- a/tests/expectations/cfg_both.c +++ b/tests/expectations/cfg_both.c @@ -77,6 +77,18 @@ typedef struct ConditionalField { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ __ConditionalField_field(0) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif +#define ConditionalField_ONE (ConditionalField){ __ConditionalField_field(1) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif typedef struct Normal { int32_t x; diff --git a/tests/expectations/cfg_both.compat.c b/tests/expectations/cfg_both.compat.c index 2377824e..6a06b78d 100644 --- a/tests/expectations/cfg_both.compat.c +++ b/tests/expectations/cfg_both.compat.c @@ -95,6 +95,18 @@ typedef struct ConditionalField { #endif ; } ConditionalField; +#define ConditionalField_ZERO (ConditionalField){ __ConditionalField_field(0) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif +#define ConditionalField_ONE (ConditionalField){ __ConditionalField_field(1) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif typedef struct Normal { int32_t x; diff --git a/tests/expectations/cfg_tag.c b/tests/expectations/cfg_tag.c index 8cc88538..ff84a233 100644 --- a/tests/expectations/cfg_tag.c +++ b/tests/expectations/cfg_tag.c @@ -77,6 +77,18 @@ struct ConditionalField { #endif ; }; +#define ConditionalField_ZERO (ConditionalField){ __ConditionalField_field(0) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif +#define ConditionalField_ONE (ConditionalField){ __ConditionalField_field(1) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif struct Normal { int32_t x; diff --git a/tests/expectations/cfg_tag.compat.c b/tests/expectations/cfg_tag.compat.c index ec976353..b67a1bff 100644 --- a/tests/expectations/cfg_tag.compat.c +++ b/tests/expectations/cfg_tag.compat.c @@ -95,6 +95,18 @@ struct ConditionalField { #endif ; }; +#define ConditionalField_ZERO (ConditionalField){ __ConditionalField_field(0) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif +#define ConditionalField_ONE (ConditionalField){ __ConditionalField_field(1) } +#if defined(X11) +#define __ConditionalField_field(v) .field = (v) +#else +#define __ConditionalField_field(v) +#endif struct Normal { int32_t x; diff --git a/tests/expectations/cfg_tag.pyx b/tests/expectations/cfg_tag.pyx index e508bb30..6a0d44d7 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 70893609..0efe3546 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)