Skip to content

Commit

Permalink
respect conditional cfg
Browse files Browse the repository at this point in the history
  • Loading branch information
scovich committed Nov 1, 2024
1 parent fe40e24 commit b99b321
Show file tree
Hide file tree
Showing 18 changed files with 356 additions and 47 deletions.
10 changes: 5 additions & 5 deletions src/bindgen/ir/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl<'a> DefineKey<'a> {
}
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Cfg {
Boolean(String),
Named(String, String),
Expand Down Expand Up @@ -129,10 +129,10 @@ impl syn::parse::Parse for Cfg {

impl Cfg {
pub fn join(cfgs: &[Cfg]) -> Option<Cfg> {
if cfgs.is_empty() {
None
} else {
Some(Cfg::All(cfgs.to_owned()))
match cfgs {
[] => None,
[cfg] => Some(cfg.clone()),
_ => Some(Cfg::All(cfgs.to_owned())),
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/bindgen/ir/enumeration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,13 @@ impl Enum {
}

pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) {
for v in &self.variants {
if let VariantBody::Body { ref body, .. } = v.body {
body.find_return_value_monomorphs(monomorphs);
monomorphs.with_active_cfg(self.cfg.clone(), |m| {
for v in &self.variants {
if let VariantBody::Body { ref body, .. } = v.body {
body.find_return_value_monomorphs(m);
}
}
}
});
}

pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
Expand Down
4 changes: 3 additions & 1 deletion src/bindgen/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ impl Function {
}

pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) {
monomorphs.handle_function(&self.ret, self.args.iter().map(|arg| &arg.ty));
monomorphs.with_active_cfg(self.cfg.clone(), |m| {
m.handle_function(&self.ret, self.args.iter().map(|arg| &arg.ty));
});
}
pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
self.ret.add_monomorphs(library, out);
Expand Down
8 changes: 5 additions & 3 deletions src/bindgen/ir/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,11 @@ impl Struct {
}

pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) {
for field in &self.fields {
field.ty.find_return_value_monomorphs(monomorphs, false);
}
monomorphs.with_active_cfg(self.cfg.clone(), |m| {
for field in &self.fields {
field.ty.find_return_value_monomorphs(m, false);
}
});
}

pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
Expand Down
6 changes: 4 additions & 2 deletions src/bindgen/ir/typedef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ impl Typedef {
monomorphs: &mut ReturnValueMonomorphs<'_>,
is_return_value: bool,
) {
self.aliased
.find_return_value_monomorphs(monomorphs, is_return_value);
monomorphs.with_active_cfg(self.cfg.clone(), |m| {
self.aliased
.find_return_value_monomorphs(m, is_return_value);
});
}

pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
Expand Down
8 changes: 5 additions & 3 deletions src/bindgen/ir/union.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ impl Union {
}

pub fn find_return_value_monomorphs(&self, monomorphs: &mut ReturnValueMonomorphs<'_>) {
for field in &self.fields {
field.ty.find_return_value_monomorphs(monomorphs, false);
}
monomorphs.with_active_cfg(self.cfg.clone(), |m| {
for field in &self.fields {
field.ty.find_return_value_monomorphs(m, false);
}
});
}

pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
Expand Down
64 changes: 44 additions & 20 deletions src/bindgen/monomorph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::iter::FromIterator as _;
use std::mem;

use crate::bindgen::ir::{
Documentation, Enum, Field, GenericArgument, GenericPath, Item, ItemContainer, OpaqueItem,
Cfg, Documentation, Enum, Field, GenericArgument, GenericPath, Item, ItemContainer, OpaqueItem,
Path, Struct, Type, Typedef, Union,
};
use crate::bindgen::library::Library;
Expand Down Expand Up @@ -152,30 +152,53 @@ impl Monomorphs {
/// functions that can lead to compilation warnings/errors if not explicitly instantiated.
pub struct ReturnValueMonomorphs<'a> {
library: &'a Library,
monomorphs: HashSet<GenericPath>,
monomorphs: HashSet<(GenericPath, Option<Cfg>)>,
active_cfgs: Vec<Cfg>,
}

impl<'a> ReturnValueMonomorphs<'a> {
pub fn new(library: &'a Library) -> Self {
Self {
library,
monomorphs: HashSet::new(),
active_cfgs: Vec::new(),
}
}

/// Resolve a typedef that is a function return value, specializing it first if needed.
fn handle_return_value_typedef(&mut self, typedef: Typedef, generic: &GenericPath) {
if typedef.is_generic() {
let args = generic.generics();
let aliased = &typedef.aliased;
let mappings = typedef.generic_params.call(typedef.path.name(), args);
let aliased = aliased.specialize(&mappings);
aliased.find_return_value_monomorphs(self, true);
fn insert(&mut self, generic: &GenericPath, cfg: Option<Cfg>) {
if !generic.generics().is_empty() {
self.with_active_cfg(cfg, |m| {
let cfg = Cfg::join(&m.active_cfgs);
m.monomorphs.insert((generic.clone(), cfg));
});
}
}

pub fn with_active_cfg(&mut self, cfg: Option<Cfg>, thunk: impl FnOnce(&mut Self)) {
if let Some(cfg) = cfg {
self.active_cfgs.push(cfg);
thunk(self);
self.active_cfgs.pop();
} else {
typedef.find_return_value_monomorphs(self, true);
thunk(self);
}
}

/// Resolve a typedef that is a function return value, specializing it first if needed.
fn handle_return_value_typedef(&mut self, typedef: Typedef, generic: &GenericPath) {
self.with_active_cfg(typedef.cfg.clone(), |m| {
if typedef.is_generic() {
let args = generic.generics();
let aliased = &typedef.aliased;
let mappings = typedef.generic_params.call(typedef.path.name(), args);
let aliased = aliased.specialize(&mappings);
aliased.find_return_value_monomorphs(m, true);
} else {
typedef.find_return_value_monomorphs(m, true);
}
});
}

/// Once we find a function return type, what we do with it depends on the type of item it
/// resolves to. Typedefs need to be resolved recursively, while generic structs, unions, and
/// enums are captured in the set of return value monomorphs.
Expand All @@ -191,16 +214,13 @@ impl<'a> ReturnValueMonomorphs<'a> {
// Opaque items cannot be instantiated (doomed to compilation failure)
ItemContainer::OpaqueItem(_) => {}
ItemContainer::Typedef(t) => self.handle_return_value_typedef(t, generic),
ItemContainer::Union(_) | ItemContainer::Enum(_) => {
if !generic.generics().is_empty() {
self.monomorphs.insert(generic.clone());
}
}
ItemContainer::Union(u) => self.insert(generic, u.cfg),
ItemContainer::Enum(e) => self.insert(generic, e.cfg),
ItemContainer::Struct(s) => {
if let Some(t) = s.as_typedef() {
self.handle_return_value_typedef(t, generic);
} else if !generic.generics().is_empty() {
self.monomorphs.insert(generic.clone());
} else {
self.insert(generic, s.cfg);
}
}
}
Expand All @@ -225,11 +245,15 @@ impl<'a> ReturnValueMonomorphs<'a> {

// Sort the output so that the struct remains stable across runs (tests want that).
let mut monomorphs = Vec::from_iter(self.monomorphs);
monomorphs.sort();
monomorphs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
let fields = monomorphs
.into_iter()
.enumerate()
.map(|(i, path)| Field::from_name_and_type(format!("field{}", i), Type::Path(path)))
.map(|(i, (path, cfg))| {
let mut f = Field::from_name_and_type(format!("field{}", i), Type::Path(path));
f.cfg = cfg;
f
})
.collect();
let doc_comment = vec![
" Dummy struct emitted by cbindgen to avoid compiler warnings/errors about",
Expand Down
28 changes: 28 additions & 0 deletions tests/expectations/return_value_monomorphs.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
#if 0
DEF DEFINE_FEATURE_1 = 0
DEF DEFINE_FEATURE_2 = 0
#endif


#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct {
uint16_t x;
} Foo_u16;

#if defined(DEFINE_FEATURE_1)
typedef Foo_u16 FooConditional_u16;
#endif

typedef struct {
int16_t x;
} Foo_i16;
Expand Down Expand Up @@ -68,6 +82,14 @@ typedef struct {

typedef Foo_i64 Transparent;

typedef struct {
uint8_t x;
} Foo_u8;

#if defined(DEFINE_FEATURE_2)
FooConditional_u16 double_feature(void);
#endif

int32_t fnA(void);

int16_t fnB(void);
Expand All @@ -91,3 +113,9 @@ Foo_bool fnL(void);
WrapNonZeroInt fnM(void);

Transparent fnN(void);

#if defined(DEFINE_FEATURE_1)
Foo_u8 fnO(void);
#endif

Foo_u8 fnP(void);
28 changes: 28 additions & 0 deletions tests/expectations/return_value_monomorphs.compat.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
#if 0
DEF DEFINE_FEATURE_1 = 0
DEF DEFINE_FEATURE_2 = 0
#endif


#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct {
uint16_t x;
} Foo_u16;

#if defined(DEFINE_FEATURE_1)
typedef Foo_u16 FooConditional_u16;
#endif

typedef struct {
int16_t x;
} Foo_i16;
Expand Down Expand Up @@ -68,10 +82,18 @@ typedef struct {

typedef Foo_i64 Transparent;

typedef struct {
uint8_t x;
} Foo_u8;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

#if defined(DEFINE_FEATURE_2)
FooConditional_u16 double_feature(void);
#endif

int32_t fnA(void);

int16_t fnB(void);
Expand All @@ -96,6 +118,12 @@ WrapNonZeroInt fnM(void);

Transparent fnN(void);

#if defined(DEFINE_FEATURE_1)
Foo_u8 fnO(void);
#endif

Foo_u8 fnP(void);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
38 changes: 34 additions & 4 deletions tests/expectations/return_value_monomorphs.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#if 0
DEF DEFINE_FEATURE_1 = 0
DEF DEFINE_FEATURE_2 = 0
#endif


#include <cstdarg>
#include <cstdint>
#include <cstdlib>
Expand All @@ -23,12 +29,26 @@ struct __cbindgen_return_value_monomorphs {
Bar<int8_t, int32_t> field2;
Bar<int16_t, int16_t> field3;
Foo<bool> field4;
Foo<int8_t> field5;
Foo<int16_t> field6;
Foo<int32_t> field7;
Foo<int64_t> field8;
#if defined(DEFINE_FEATURE_1)
Foo<uint8_t> field5
#endif
;
Foo<uint8_t> field6;
#if (defined(DEFINE_FEATURE_2) && defined(DEFINE_FEATURE_1))
Foo<uint16_t> field7
#endif
;
Foo<int8_t> field8;
Foo<int16_t> field9;
Foo<int32_t> field10;
Foo<int64_t> field11;
};

#if defined(DEFINE_FEATURE_1)
template<typename T>
using FooConditional = Foo<T>;
#endif

template<typename T>
struct NotReturnValue {
T x;
Expand Down Expand Up @@ -57,6 +77,10 @@ using Transparent = Foo<int64_t>;

extern "C" {

#if defined(DEFINE_FEATURE_2)
FooConditional<uint16_t> double_feature();
#endif

int32_t fnA();

int16_t fnB();
Expand All @@ -81,4 +105,10 @@ WrapNonZeroInt fnM();

Transparent fnN();

#if defined(DEFINE_FEATURE_1)
Foo<uint8_t> fnO();
#endif

Foo<uint8_t> fnP();

} // extern "C"
Loading

0 comments on commit b99b321

Please sign in to comment.