From caf69c8800085eccffa739817654abc596297336 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 10 May 2022 17:11:42 -0500 Subject: [PATCH] Support bool and char literals as arguments to const generics. --- src/bindgen/ir/ty.rs | 8 +++ tests/expectations/const_generics_bool.both.c | 36 ++++++++++++ .../const_generics_bool.both.compat.c | 44 ++++++++++++++ tests/expectations/const_generics_bool.c | 36 ++++++++++++ .../expectations/const_generics_bool.compat.c | 44 ++++++++++++++ tests/expectations/const_generics_bool.cpp | 37 ++++++++++++ tests/expectations/const_generics_bool.pyx | 37 ++++++++++++ tests/expectations/const_generics_bool.tag.c | 36 ++++++++++++ .../const_generics_bool.tag.compat.c | 44 ++++++++++++++ .../expectations/const_generics_bool.tag.pyx | 37 ++++++++++++ tests/expectations/const_generics_char.both.c | 12 ++++ .../const_generics_char.both.compat.c | 20 +++++++ tests/expectations/const_generics_char.c | 12 ++++ .../expectations/const_generics_char.compat.c | 20 +++++++ tests/expectations/const_generics_char.cpp | 18 ++++++ tests/expectations/const_generics_char.pyx | 14 +++++ tests/expectations/const_generics_char.tag.c | 12 ++++ .../const_generics_char.tag.compat.c | 20 +++++++ .../expectations/const_generics_char.tag.pyx | 14 +++++ tests/rust/const_generics_bool.rs | 57 +++++++++++++++++++ tests/rust/const_generics_char.rs | 20 +++++++ 21 files changed, 578 insertions(+) create mode 100644 tests/expectations/const_generics_bool.both.c create mode 100644 tests/expectations/const_generics_bool.both.compat.c create mode 100644 tests/expectations/const_generics_bool.c create mode 100644 tests/expectations/const_generics_bool.compat.c create mode 100644 tests/expectations/const_generics_bool.cpp create mode 100644 tests/expectations/const_generics_bool.pyx create mode 100644 tests/expectations/const_generics_bool.tag.c create mode 100644 tests/expectations/const_generics_bool.tag.compat.c create mode 100644 tests/expectations/const_generics_bool.tag.pyx create mode 100644 tests/expectations/const_generics_char.both.c create mode 100644 tests/expectations/const_generics_char.both.compat.c create mode 100644 tests/expectations/const_generics_char.c create mode 100644 tests/expectations/const_generics_char.compat.c create mode 100644 tests/expectations/const_generics_char.cpp create mode 100644 tests/expectations/const_generics_char.pyx create mode 100644 tests/expectations/const_generics_char.tag.c create mode 100644 tests/expectations/const_generics_char.tag.compat.c create mode 100644 tests/expectations/const_generics_char.tag.pyx create mode 100644 tests/rust/const_generics_bool.rs create mode 100644 tests/rust/const_generics_char.rs diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 0e318e2..fb3c3bd 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -340,6 +340,14 @@ impl ConstExpr { lit: syn::Lit::Int(ref len), .. }) => Ok(ConstExpr::Value(len.base10_digits().to_string())), + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Bool(syn::LitBool { value, .. }), + .. + }) => Ok(ConstExpr::Value(value.to_string())), + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Char(ref ch), + .. + }) => Ok(ConstExpr::Value(u32::to_string(&ch.value().into()))), syn::Expr::Path(ref path) => { let generic_path = GenericPath::load(&path.path)?; Ok(ConstExpr::Name(generic_path.export_name().to_owned())) diff --git a/tests/expectations/const_generics_bool.both.c b/tests/expectations/const_generics_bool.both.c new file mode 100644 index 0000000..c693f41 --- /dev/null +++ b/tests/expectations/const_generics_bool.both.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +typedef const char *Str; + +typedef struct HashTable_Str__c_char__false { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; +} HashTable_Str__c_char__false; + +typedef struct HashTable_Str__c_char__false MySet; + +typedef void (*SetCallback)(Str key); + +typedef struct HashTable_Str__u64__true { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; +} HashTable_Str__u64__true; + +typedef void (*MapCallback)(Str key, uint64_t val); + +MySet *new_set(void); + +void set_for_each(const MySet *set, SetCallback callback); + +struct HashTable_Str__u64__true *new_map(void); + +void map_for_each(const struct HashTable_Str__u64__true *map, MapCallback callback); diff --git a/tests/expectations/const_generics_bool.both.compat.c b/tests/expectations/const_generics_bool.both.compat.c new file mode 100644 index 0000000..ad87976 --- /dev/null +++ b/tests/expectations/const_generics_bool.both.compat.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +typedef const char *Str; + +typedef struct HashTable_Str__c_char__false { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; +} HashTable_Str__c_char__false; + +typedef struct HashTable_Str__c_char__false MySet; + +typedef void (*SetCallback)(Str key); + +typedef struct HashTable_Str__u64__true { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; +} HashTable_Str__u64__true; + +typedef void (*MapCallback)(Str key, uint64_t val); + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +MySet *new_set(void); + +void set_for_each(const MySet *set, SetCallback callback); + +struct HashTable_Str__u64__true *new_map(void); + +void map_for_each(const struct HashTable_Str__u64__true *map, MapCallback callback); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_bool.c b/tests/expectations/const_generics_bool.c new file mode 100644 index 0000000..3ed168d --- /dev/null +++ b/tests/expectations/const_generics_bool.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +typedef const char *Str; + +typedef struct { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; +} HashTable_Str__c_char__false; + +typedef HashTable_Str__c_char__false MySet; + +typedef void (*SetCallback)(Str key); + +typedef struct { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; +} HashTable_Str__u64__true; + +typedef void (*MapCallback)(Str key, uint64_t val); + +MySet *new_set(void); + +void set_for_each(const MySet *set, SetCallback callback); + +HashTable_Str__u64__true *new_map(void); + +void map_for_each(const HashTable_Str__u64__true *map, MapCallback callback); diff --git a/tests/expectations/const_generics_bool.compat.c b/tests/expectations/const_generics_bool.compat.c new file mode 100644 index 0000000..304c38d --- /dev/null +++ b/tests/expectations/const_generics_bool.compat.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +typedef const char *Str; + +typedef struct { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; +} HashTable_Str__c_char__false; + +typedef HashTable_Str__c_char__false MySet; + +typedef void (*SetCallback)(Str key); + +typedef struct { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; +} HashTable_Str__u64__true; + +typedef void (*MapCallback)(Str key, uint64_t val); + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +MySet *new_set(void); + +void set_for_each(const MySet *set, SetCallback callback); + +HashTable_Str__u64__true *new_map(void); + +void map_for_each(const HashTable_Str__u64__true *map, MapCallback callback); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_bool.cpp b/tests/expectations/const_generics_bool.cpp new file mode 100644 index 0000000..f2ee08b --- /dev/null +++ b/tests/expectations/const_generics_bool.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +template +struct MaybeUninit; + +using Str = const char*; + +template +struct HashTable { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + MaybeUninit *keys; + MaybeUninit *vals; +}; + +using MySet = HashTable; + +using SetCallback = void(*)(Str key); + +using MapCallback = void(*)(Str key, uint64_t val); + +extern "C" { + +MySet *new_set(); + +void set_for_each(const MySet *set, SetCallback callback); + +HashTable *new_map(); + +void map_for_each(const HashTable *map, MapCallback callback); + +} // extern "C" diff --git a/tests/expectations/const_generics_bool.pyx b/tests/expectations/const_generics_bool.pyx new file mode 100644 index 0000000..a219992 --- /dev/null +++ b/tests/expectations/const_generics_bool.pyx @@ -0,0 +1,37 @@ +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 const char *Str; + + ctypedef struct HashTable_Str__c_char__false: + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; + + ctypedef HashTable_Str__c_char__false MySet; + + ctypedef void (*SetCallback)(Str key); + + ctypedef struct HashTable_Str__u64__true: + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; + + ctypedef void (*MapCallback)(Str key, uint64_t val); + + MySet *new_set(); + + void set_for_each(const MySet *set, SetCallback callback); + + HashTable_Str__u64__true *new_map(); + + void map_for_each(const HashTable_Str__u64__true *map, MapCallback callback); diff --git a/tests/expectations/const_generics_bool.tag.c b/tests/expectations/const_generics_bool.tag.c new file mode 100644 index 0000000..8cb1df0 --- /dev/null +++ b/tests/expectations/const_generics_bool.tag.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +typedef const char *Str; + +struct HashTable_Str__c_char__false { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; +}; + +typedef struct HashTable_Str__c_char__false MySet; + +typedef void (*SetCallback)(Str key); + +struct HashTable_Str__u64__true { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; +}; + +typedef void (*MapCallback)(Str key, uint64_t val); + +MySet *new_set(void); + +void set_for_each(const MySet *set, SetCallback callback); + +struct HashTable_Str__u64__true *new_map(void); + +void map_for_each(const struct HashTable_Str__u64__true *map, MapCallback callback); diff --git a/tests/expectations/const_generics_bool.tag.compat.c b/tests/expectations/const_generics_bool.tag.compat.c new file mode 100644 index 0000000..4b12798 --- /dev/null +++ b/tests/expectations/const_generics_bool.tag.compat.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +typedef const char *Str; + +struct HashTable_Str__c_char__false { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; +}; + +typedef struct HashTable_Str__c_char__false MySet; + +typedef void (*SetCallback)(Str key); + +struct HashTable_Str__u64__true { + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; +}; + +typedef void (*MapCallback)(Str key, uint64_t val); + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +MySet *new_set(void); + +void set_for_each(const MySet *set, SetCallback callback); + +struct HashTable_Str__u64__true *new_map(void); + +void map_for_each(const struct HashTable_Str__u64__true *map, MapCallback callback); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_bool.tag.pyx b/tests/expectations/const_generics_bool.tag.pyx new file mode 100644 index 0000000..54cf04a --- /dev/null +++ b/tests/expectations/const_generics_bool.tag.pyx @@ -0,0 +1,37 @@ +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 const char *Str; + + cdef struct HashTable_Str__c_char__false: + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + char *vals; + + ctypedef HashTable_Str__c_char__false MySet; + + ctypedef void (*SetCallback)(Str key); + + cdef struct HashTable_Str__u64__true: + uintptr_t num_buckets; + uintptr_t capacity; + uint8_t *occupied; + Str *keys; + uint64_t *vals; + + ctypedef void (*MapCallback)(Str key, uint64_t val); + + MySet *new_set(); + + void set_for_each(const MySet *set, SetCallback callback); + + HashTable_Str__u64__true *new_map(); + + void map_for_each(const HashTable_Str__u64__true *map, MapCallback callback); diff --git a/tests/expectations/const_generics_char.both.c b/tests/expectations/const_generics_char.both.c new file mode 100644 index 0000000..4cd9041 --- /dev/null +++ b/tests/expectations/const_generics_char.both.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +typedef struct TakeUntil_0 { + const uint8_t *start; + uintptr_t len; + uintptr_t point; +} TakeUntil_0; + +struct TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); diff --git a/tests/expectations/const_generics_char.both.compat.c b/tests/expectations/const_generics_char.both.compat.c new file mode 100644 index 0000000..65f152e --- /dev/null +++ b/tests/expectations/const_generics_char.both.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +typedef struct TakeUntil_0 { + const uint8_t *start; + uintptr_t len; + uintptr_t point; +} TakeUntil_0; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_char.c b/tests/expectations/const_generics_char.c new file mode 100644 index 0000000..fb50a01 --- /dev/null +++ b/tests/expectations/const_generics_char.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +typedef struct { + const uint8_t *start; + uintptr_t len; + uintptr_t point; +} TakeUntil_0; + +TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); diff --git a/tests/expectations/const_generics_char.compat.c b/tests/expectations/const_generics_char.compat.c new file mode 100644 index 0000000..7ea7ba0 --- /dev/null +++ b/tests/expectations/const_generics_char.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +typedef struct { + const uint8_t *start; + uintptr_t len; + uintptr_t point; +} TakeUntil_0; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_char.cpp b/tests/expectations/const_generics_char.cpp new file mode 100644 index 0000000..22376cc --- /dev/null +++ b/tests/expectations/const_generics_char.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +template +struct TakeUntil { + const uint8_t *start; + uintptr_t len; + uintptr_t point; +}; + +extern "C" { + +TakeUntil<0> until_nul(const uint8_t *start, uintptr_t len); + +} // extern "C" diff --git a/tests/expectations/const_generics_char.pyx b/tests/expectations/const_generics_char.pyx new file mode 100644 index 0000000..4e3bfe8 --- /dev/null +++ b/tests/expectations/const_generics_char.pyx @@ -0,0 +1,14 @@ +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 TakeUntil_0: + const uint8_t *start; + uintptr_t len; + uintptr_t point; + + TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); diff --git a/tests/expectations/const_generics_char.tag.c b/tests/expectations/const_generics_char.tag.c new file mode 100644 index 0000000..a6cb5ff --- /dev/null +++ b/tests/expectations/const_generics_char.tag.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +struct TakeUntil_0 { + const uint8_t *start; + uintptr_t len; + uintptr_t point; +}; + +struct TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); diff --git a/tests/expectations/const_generics_char.tag.compat.c b/tests/expectations/const_generics_char.tag.compat.c new file mode 100644 index 0000000..71c01fb --- /dev/null +++ b/tests/expectations/const_generics_char.tag.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +struct TakeUntil_0 { + const uint8_t *start; + uintptr_t len; + uintptr_t point; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_char.tag.pyx b/tests/expectations/const_generics_char.tag.pyx new file mode 100644 index 0000000..eaaa95f --- /dev/null +++ b/tests/expectations/const_generics_char.tag.pyx @@ -0,0 +1,14 @@ +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 TakeUntil_0: + const uint8_t *start; + uintptr_t len; + uintptr_t point; + + TakeUntil_0 until_nul(const uint8_t *start, uintptr_t len); diff --git a/tests/rust/const_generics_bool.rs b/tests/rust/const_generics_bool.rs new file mode 100644 index 0000000..3047b07 --- /dev/null +++ b/tests/rust/const_generics_bool.rs @@ -0,0 +1,57 @@ +use std::mem::MaybeUninit; + +use libc::c_char; + +#[repr(C)] +pub struct HashTable { + num_buckets: usize, + capacity: usize, + occupied: *mut u8, + keys: *mut MaybeUninit, + vals: *mut MaybeUninit, +} + +type Str = *const c_char; +pub type HashMap = HashTable; +pub type HashSet = HashTable; + +impl HashTable +{ + pub fn new() -> Self { + HashTable { + num_buckets: 0, + capacity: 0, + occupied: std::ptr::null_mut(), + keys: std::ptr::null_mut(), + vals: std::ptr::null_mut(), + } + } +} + +// with alias +type MySet = HashTable; + +#[no_mangle] +pub extern "C" fn new_set() -> *mut MySet { + Box::into_raw(Box::new(HashSet::new())) +} + +type SetCallback = unsafe extern "C" fn(key: Str); + +#[no_mangle] +pub unsafe extern "C" fn set_for_each(set: *const MySet, callback: SetCallback) { + todo!(); +} + +// without alias +#[no_mangle] +pub extern "C" fn new_map() -> *mut HashTable { + Box::into_raw(Box::new(HashMap::new())) +} + +type MapCallback = unsafe extern "C" fn(key: Str, val: u64); + +#[no_mangle] +pub unsafe extern "C" fn map_for_each(map: *const HashTable, callback: MapCallback) { + todo!(); +} diff --git a/tests/rust/const_generics_char.rs b/tests/rust/const_generics_char.rs new file mode 100644 index 0000000..85bff32 --- /dev/null +++ b/tests/rust/const_generics_char.rs @@ -0,0 +1,20 @@ +use std::marker::PhantomData; + +#[repr(C)] +struct TakeUntil<'a, const V: char> +{ + marker: PhantomData<&'a str>, + start: *const u8, + len: usize, + point: usize, +} + +#[no_mangle] +pub unsafe extern "C" fn until_nul(start: *const u8, len: usize) -> TakeUntil<'a, '\0'> { + TakeUntil { + marker: PhantomData, + start, + len, + point: 0, + } +}