Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply defines to struct literal #956

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 31 additions & 21 deletions src/bindgen/ir/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,33 +328,43 @@ pub trait ConditionWrite {
fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
}

impl ConditionWrite for Condition {
fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
if config.language == Language::Cython {
out.write("IF ");
self.write(config, out);
out.open_brace();
} else {
out.push_set_spaces(0);
out.write("#if ");
self.write(config, out);
out.pop_set_spaces();
out.new_line();
}
}

fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
if config.language == Language::Cython {
out.close_brace(false);
} else {
out.new_line();
out.push_set_spaces(0);
out.write("#endif");
out.pop_set_spaces();
}
}
}

impl ConditionWrite for Option<Condition> {
fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
if let Some(ref cfg) = *self {
if config.language == Language::Cython {
out.write("IF ");
cfg.write(config, out);
out.open_brace();
} else {
out.push_set_spaces(0);
out.write("#if ");
cfg.write(config, out);
out.pop_set_spaces();
out.new_line();
}
if let Some(cfg) = self {
cfg.write_before(config, out)
}
}

fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
if self.is_some() {
if config.language == Language::Cython {
out.close_brace(false);
} else {
out.new_line();
out.push_set_spaces(0);
out.write("#endif");
out.pop_set_spaces();
}
if let Some(cfg) = self {
cfg.write_after(config, out);
}
}
}
27 changes: 18 additions & 9 deletions src/bindgen/ir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Cfg>,
}

#[derive(Debug, Clone)]
pub enum Literal {
Expr(String),
Expand All @@ -101,7 +107,7 @@ pub enum Literal {
Struct {
path: Path,
export_name: String,
fields: HashMap<String, Literal>,
fields: HashMap<String, LiteralStructField>,
},
Cast {
ty: Type,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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, .. } => {
Expand Down Expand Up @@ -388,12 +394,13 @@ impl Literal {
} => name,
_ => return Err(format!("Unsupported call expression. {:?}", *expr)),
};
let mut fields = HashMap::<String, Literal>::default();
let mut fields = HashMap::<String, LiteralStructField>::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()),
Expand All @@ -408,11 +415,13 @@ impl Literal {
..
}) => {
let struct_name = path.segments[0].ident.unraw().to_string();
let mut field_map = HashMap::<String, Literal>::default();
let mut field_map = HashMap::<String, LiteralStructField>::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()),
Expand Down Expand Up @@ -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());
Expand Down
49 changes: 39 additions & 10 deletions src/bindgen/language_backend/clike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -912,13 +924,12 @@ 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);
self.write_literal(out, lit);
write_field_name!(out, ordered_key);
self.write_literal(out, &lit.value);
if i + 1 != ordered_fields.len() {
write!(out, ",");
if !is_constexpr {
Expand All @@ -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);
}
}
}
Expand All @@ -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);
}
}
}
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/bindgen/language_backend/cython.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, " }}");
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/cfg.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ typedef struct {
#endif
;
} ConditionalField;
#define ConditionalField_ZERO (ConditionalField){ __ConditionalField_field(0) }
#if defined(X11)
youknowone marked this conversation as resolved.
Show resolved Hide resolved
#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;
Expand Down
6 changes: 6 additions & 0 deletions tests/expectations/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions tests/expectations/cfg.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ cdef extern from *:

ctypedef struct ConditionalField:
int32_t field;
const ConditionalField ConditionalField_ZERO # = <ConditionalField>{ 0 }
const ConditionalField ConditionalField_ONE # = <ConditionalField>{ 1 }

ctypedef struct Normal:
int32_t x;
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/cfg_both.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/cfg_both.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/cfg_tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/cfg_tag.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions tests/expectations/cfg_tag.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ cdef extern from *:

cdef struct ConditionalField:
int32_t field;
const ConditionalField ConditionalField_ZERO # = <ConditionalField>{ 0 }
const ConditionalField ConditionalField_ONE # = <ConditionalField>{ 1 }

cdef struct Normal:
int32_t x;
Expand Down
Loading
Loading