From ff2c1bf7c4ea265d4859c77d81090bdf42340426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 14 Jan 2021 21:45:31 +0100 Subject: [PATCH] ir: Handle NonZero and simplify Option like we simplify Option. Fixes #646 --- src/bindgen/ir/ty.rs | 67 +++++++++++++++++++++++- tests/expectations/nonzero.both.c | 44 ++++++++++++++++ tests/expectations/nonzero.both.compat.c | 52 ++++++++++++++++++ tests/expectations/nonzero.c | 44 ++++++++++++++++ tests/expectations/nonzero.compat.c | 52 ++++++++++++++++++ tests/expectations/nonzero.cpp | 50 ++++++++++++++++++ tests/expectations/nonzero.pyx | 47 +++++++++++++++++ tests/expectations/nonzero.tag.c | 44 ++++++++++++++++ tests/expectations/nonzero.tag.compat.c | 52 ++++++++++++++++++ tests/expectations/nonzero.tag.pyx | 47 +++++++++++++++++ tests/rust/nonzero.rs | 30 +++++++++++ tests/rust/nonzero.toml | 13 +++++ 12 files changed, 541 insertions(+), 1 deletion(-) create mode 100644 tests/expectations/nonzero.both.c create mode 100644 tests/expectations/nonzero.both.compat.c create mode 100644 tests/expectations/nonzero.c create mode 100644 tests/expectations/nonzero.compat.c create mode 100644 tests/expectations/nonzero.cpp create mode 100644 tests/expectations/nonzero.pyx create mode 100644 tests/expectations/nonzero.tag.c create mode 100644 tests/expectations/nonzero.tag.compat.c create mode 100644 tests/expectations/nonzero.tag.pyx create mode 100644 tests/rust/nonzero.rs create mode 100644 tests/rust/nonzero.toml diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index e06ed1ac7..8e9ffd508 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -517,6 +517,23 @@ impl Type { } } + pub fn make_zeroable(&self) -> Option { + let (kind, signed) = match *self { + Type::Primitive(PrimitiveType::Integer { + zeroable: false, + kind, + signed, + }) => (kind, signed), + _ => return None, + }; + + Some(Type::Primitive(PrimitiveType::Integer { + kind, + signed, + zeroable: true, + })) + } + pub fn make_nullable(&self) -> Option { match *self { Type::Ptr { @@ -543,12 +560,52 @@ impl Type { } } + fn nonzero_to_primitive(&self) -> Option { + let path = match *self { + Type::Path(ref p) => p, + _ => return None, + }; + + if !path.generics().is_empty() { + return None; + } + + let name = path.name(); + if !name.starts_with("NonZero") { + return None; + } + + let (kind, signed) = match path.name() { + "NonZeroU8" => (IntKind::B8, false), + "NonZeroU16" => (IntKind::B16, false), + "NonZeroU32" => (IntKind::B32, false), + "NonZeroU64" => (IntKind::B64, false), + "NonZeroUSize" => (IntKind::Size, false), + "NonZeroI8" => (IntKind::B8, true), + "NonZeroI16" => (IntKind::B16, true), + "NonZeroI32" => (IntKind::B32, true), + "NonZeroI64" => (IntKind::B64, true), + "NonZeroISize" => (IntKind::Size, true), + _ => return None, + }; + + Some(Type::Primitive(PrimitiveType::Integer { + zeroable: false, + signed, + kind, + })) + } + fn simplified_type(&self, config: &Config) -> Option { let path = match *self { Type::Path(ref p) => p, _ => return None, }; + if path.generics().is_empty() { + return self.nonzero_to_primitive(); + } + if path.generics().len() != 1 { return None; } @@ -559,7 +616,15 @@ impl Type { None => Cow::Borrowed(unsimplified_generic), }; match path.name() { - "Option" => generic.make_nullable(), + "Option" => { + if let Some(nullable) = generic.make_nullable() { + return Some(nullable); + } + if let Some(zeroable) = generic.make_zeroable() { + return Some(zeroable); + } + None + } "NonNull" => Some(Type::Ptr { ty: Box::new(generic.into_owned()), is_const: false, diff --git a/tests/expectations/nonzero.both.c b/tests/expectations/nonzero.both.c new file mode 100644 index 000000000..2aa8212f9 --- /dev/null +++ b/tests/expectations/nonzero.both.c @@ -0,0 +1,44 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +#include +#include +#include +#include + +typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64; + +typedef struct NonZeroTest { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const struct Option_Option_NonZeroI64 *j; +} NonZeroTest; + +void root(struct NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const struct Option_Option_NonZeroI64 *j); diff --git a/tests/expectations/nonzero.both.compat.c b/tests/expectations/nonzero.both.compat.c new file mode 100644 index 000000000..6708cd7e0 --- /dev/null +++ b/tests/expectations/nonzero.both.compat.c @@ -0,0 +1,52 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +#include +#include +#include +#include + +typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64; + +typedef struct NonZeroTest { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const struct Option_Option_NonZeroI64 *j; +} NonZeroTest; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(struct NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const struct Option_Option_NonZeroI64 *j); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nonzero.c b/tests/expectations/nonzero.c new file mode 100644 index 000000000..124b8beac --- /dev/null +++ b/tests/expectations/nonzero.c @@ -0,0 +1,44 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +#include +#include +#include +#include + +typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64; + +typedef struct { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const Option_Option_NonZeroI64 *j; +} NonZeroTest; + +void root(NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const Option_Option_NonZeroI64 *j); diff --git a/tests/expectations/nonzero.compat.c b/tests/expectations/nonzero.compat.c new file mode 100644 index 000000000..c4f2587bf --- /dev/null +++ b/tests/expectations/nonzero.compat.c @@ -0,0 +1,52 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +#include +#include +#include +#include + +typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64; + +typedef struct { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const Option_Option_NonZeroI64 *j; +} NonZeroTest; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const Option_Option_NonZeroI64 *j); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nonzero.cpp b/tests/expectations/nonzero.cpp new file mode 100644 index 000000000..9aef0559a --- /dev/null +++ b/tests/expectations/nonzero.cpp @@ -0,0 +1,50 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +#include +#include +#include +#include +#include + +template +struct Option; + +struct NonZeroTest { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const Option> *j; +}; + +extern "C" { + +void root(NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const Option> *j); + +} // extern "C" diff --git a/tests/expectations/nonzero.pyx b/tests/expectations/nonzero.pyx new file mode 100644 index 000000000..ef05cc184 --- /dev/null +++ b/tests/expectations/nonzero.pyx @@ -0,0 +1,47 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef struct Option_Option_NonZeroI64: + pass + + ctypedef struct NonZeroTest: + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const Option_Option_NonZeroI64 *j; + + void root(NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const Option_Option_NonZeroI64 *j); diff --git a/tests/expectations/nonzero.tag.c b/tests/expectations/nonzero.tag.c new file mode 100644 index 000000000..4e11a12d2 --- /dev/null +++ b/tests/expectations/nonzero.tag.c @@ -0,0 +1,44 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +#include +#include +#include +#include + +struct Option_Option_NonZeroI64; + +struct NonZeroTest { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const struct Option_Option_NonZeroI64 *j; +}; + +void root(struct NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const struct Option_Option_NonZeroI64 *j); diff --git a/tests/expectations/nonzero.tag.compat.c b/tests/expectations/nonzero.tag.compat.c new file mode 100644 index 000000000..e1ff2fb48 --- /dev/null +++ b/tests/expectations/nonzero.tag.compat.c @@ -0,0 +1,52 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +#include +#include +#include +#include + +struct Option_Option_NonZeroI64; + +struct NonZeroTest { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const struct Option_Option_NonZeroI64 *j; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(struct NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const struct Option_Option_NonZeroI64 *j); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/nonzero.tag.pyx b/tests/expectations/nonzero.tag.pyx new file mode 100644 index 000000000..b3bba7237 --- /dev/null +++ b/tests/expectations/nonzero.tag.pyx @@ -0,0 +1,47 @@ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif + + +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + cdef struct Option_Option_NonZeroI64: + pass + + cdef struct NonZeroTest: + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int64_t i; + const Option_Option_NonZeroI64 *j; + + void root(NonZeroTest test, + uint8_t a, + uint16_t b, + uint32_t c, + uint64_t d, + int8_t e, + int16_t f, + int32_t g, + int64_t h, + int64_t i, + const Option_Option_NonZeroI64 *j); diff --git a/tests/rust/nonzero.rs b/tests/rust/nonzero.rs new file mode 100644 index 000000000..9bc2cde27 --- /dev/null +++ b/tests/rust/nonzero.rs @@ -0,0 +1,30 @@ +use std::num::*; + +#[repr(C)] +pub struct NonZeroTest { + pub a: NonZeroU8, + pub b: NonZeroU16, + pub c: NonZeroU32, + pub d: NonZeroU64, + pub e: NonZeroI8, + pub f: NonZeroI16, + pub g: NonZeroI32, + pub h: NonZeroI64, + pub i: Option, + pub j: *const Option>, +} + +#[no_mangle] +pub extern "C" fn root( + test: NonZeroTest, + a: NonZeroU8, + b: NonZeroU16, + c: NonZeroU32, + d: NonZeroU64, + e: NonZeroI8, + f: NonZeroI16, + g: NonZeroI32, + h: NonZeroI64, + i: Option, + j: *const Option>, +) {} diff --git a/tests/rust/nonzero.toml b/tests/rust/nonzero.toml new file mode 100644 index 000000000..3c656dc7c --- /dev/null +++ b/tests/rust/nonzero.toml @@ -0,0 +1,13 @@ +header = """ +#if 0 +''' ' +#endif + +#ifdef __cplusplus +struct NonZeroI64; +#endif + +#if 0 +' ''' +#endif +"""