diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 1018e09d8..a01d81797 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -5,7 +5,7 @@ use std::io::Write; use crate::bindgen::declarationtyperesolver::DeclarationType; -use crate::bindgen::ir::{ArrayLength, Function, GenericArgument, Type}; +use crate::bindgen::ir::{ConstExpr, Function, GenericArgument, Type}; use crate::bindgen::writer::{ListType, SourceWriter}; use crate::bindgen::{Config, Language}; @@ -70,7 +70,7 @@ impl CDecl { t ), }; - let ptr_as_array = Type::Array(ty.clone(), ArrayLength::Value(length.to_string())); + let ptr_as_array = Type::Array(ty.clone(), ConstExpr::Value(length.to_string())); cdecl.build_type(&ptr_as_array, *is_const, config); cdecl } diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index e9f362097..861d51a07 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -6,7 +6,7 @@ use syn::ext::IdentExt; use crate::bindgen::cdecl; use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::{DeclarationType, DeclarationTypeResolver}; -use crate::bindgen::ir::{ArrayLength, Path, Type}; +use crate::bindgen::ir::{ConstExpr, Path, Type}; use crate::bindgen::utilities::IterHelpers; use crate::bindgen::writer::{Source, SourceWriter}; @@ -153,7 +153,7 @@ impl Source for GenericParams { #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum GenericArgument { Type(Type), - Const(ArrayLength), + Const(ConstExpr), } impl GenericArgument { @@ -275,7 +275,7 @@ impl GenericPath { syn::GenericArgument::Type(ref x) => Ok(Type::load(x)?.map(GenericArgument::Type)), syn::GenericArgument::Lifetime(_) => Ok(None), syn::GenericArgument::Const(ref x) => { - Ok(Some(GenericArgument::Const(ArrayLength::load(x)?))) + Ok(Some(GenericArgument::Const(ConstExpr::load(x)?))) } _ => Err(format!("can't handle generic argument {:?}", x)), })?, diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index cd52fec72..c08020b10 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -311,43 +311,52 @@ impl PrimitiveType { } } -// The `U` part of `[T; U]` +/// Constant expressions. +/// +/// Used for the `U` part of `[T; U]` and const generics. We support a very +/// limited vocabulary here: only identifiers and literals. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum ArrayLength { +pub enum ConstExpr { Name(String), Value(String), } -impl ArrayLength { +impl ConstExpr { pub fn as_str(&self) -> &str { match *self { - ArrayLength::Name(ref string) | ArrayLength::Value(ref string) => string, + ConstExpr::Name(ref string) | ConstExpr::Value(ref string) => string, } } pub fn rename_for_config(&mut self, config: &Config) { - if let ArrayLength::Name(ref mut name) = self { + if let ConstExpr::Name(ref mut name) = self { config.export.rename(name); } } pub fn load(expr: &syn::Expr) -> Result { match *expr { - syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Int(ref len), - .. - }) => Ok(ArrayLength::Value(len.base10_digits().to_string())), + syn::Expr::Lit(syn::ExprLit { ref lit, .. }) => { + let val = match *lit { + syn::Lit::Bool(syn::LitBool { value, .. }) => value.to_string(), + syn::Lit::Int(ref len) => len.base10_digits().to_string(), + syn::Lit::Byte(ref byte) => u8::to_string(&byte.value()), + syn::Lit::Char(ref ch) => u32::to_string(&ch.value().into()), + _ => return Err(format!("can't handle const expression {:?}", lit)), + }; + Ok(ConstExpr::Value(val)) + } syn::Expr::Path(ref path) => { let generic_path = GenericPath::load(&path.path)?; - Ok(ArrayLength::Name(generic_path.export_name().to_owned())) + Ok(ConstExpr::Name(generic_path.export_name().to_owned())) } _ => Err(format!("can't handle const expression {:?}", expr)), } } - pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> ArrayLength { + pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> ConstExpr { match *self { - ArrayLength::Name(ref name) => { + ConstExpr::Name(ref name) => { let path = Path::new(name); for &(param, value) in mappings { if path == *param { @@ -356,7 +365,7 @@ impl ArrayLength { if path.is_single_identifier() => { // This happens when the generic argument is a path. - return ArrayLength::Name(path.name().to_string()); + return ConstExpr::Name(path.name().to_string()); } GenericArgument::Const(ref expr) => { return expr.clone(); @@ -368,13 +377,13 @@ impl ArrayLength { } } } - ArrayLength::Value(_) => {} + ConstExpr::Value(_) => {} } self.clone() } } -impl Source for ArrayLength { +impl Source for ConstExpr { fn write(&self, _config: &Config, out: &mut SourceWriter) { write!(out, "{}", self.as_str()); } @@ -393,7 +402,7 @@ pub enum Type { }, Path(GenericPath), Primitive(PrimitiveType), - Array(Box, ArrayLength), + Array(Box, ConstExpr), FuncPtr { ret: Box, args: Vec<(Option, Type)>, @@ -472,7 +481,7 @@ impl Type { None => return Err("Cannot have an array of zero sized types.".to_owned()), }; - let len = ArrayLength::load(len)?; + let len = ConstExpr::load(len)?; Type::Array(Box::new(converted), len) } syn::Type::BareFn(ref function) => { diff --git a/src/bindgen/mangle.rs b/src/bindgen/mangle.rs index c61255e6c..f20bb3ce9 100644 --- a/src/bindgen/mangle.rs +++ b/src/bindgen/mangle.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use crate::bindgen::config::MangleConfig; -use crate::bindgen::ir::{ArrayLength, GenericArgument, GenericPath, Path, Type}; +use crate::bindgen::ir::{ConstExpr, GenericArgument, GenericPath, Path, Type}; use crate::bindgen::rename::IdentifierType; pub fn mangle_path(path: &Path, generic_values: &[GenericArgument], config: &MangleConfig) -> Path { @@ -71,14 +71,14 @@ impl<'a> Mangler<'a> { fn append_mangled_argument(&mut self, arg: &GenericArgument, last: bool) { match *arg { GenericArgument::Type(ref ty) => self.append_mangled_type(ty, last), - GenericArgument::Const(ArrayLength::Name(ref name)) => { + GenericArgument::Const(ConstExpr::Name(ref name)) => { // This must behave the same as a GenericArgument::Type, // because const arguments are commonly represented as Types; // see the comment on `enum GenericArgument`. let fake_ty = Type::Path(GenericPath::new(Path::new(name), vec![])); self.append_mangled_type(&fake_ty, last); } - GenericArgument::Const(ArrayLength::Value(ref val)) => self.output.push_str(val), + GenericArgument::Const(ConstExpr::Value(ref val)) => self.output.push_str(val), } } @@ -310,7 +310,7 @@ fn generics() { assert_eq!( mangle_path( &Path::new("Top"), - &[GenericArgument::Const(ArrayLength::Value("40".to_string()))], + &[GenericArgument::Const(ConstExpr::Value("40".to_string()))], &MangleConfig::default(), ), Path::new("Top_40") @@ -319,7 +319,7 @@ fn generics() { assert_eq!( mangle_path( &Path::new("Top"), - &[GenericArgument::Const(ArrayLength::Name("N".to_string()))], + &[GenericArgument::Const(ConstExpr::Name("N".to_string()))], &MangleConfig::default(), ), Path::new("Top_N") @@ -339,7 +339,7 @@ fn generics() { &Path::new("Foo"), &[ float(), - GenericArgument::Const(ArrayLength::Value("40".to_string())) + GenericArgument::Const(ConstExpr::Value("40".to_string())) ], &MangleConfig::default(), ), diff --git a/tests/expectations/const_generics_bool.both.c b/tests/expectations/const_generics_bool.both.c new file mode 100644 index 000000000..c693f41b6 --- /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 000000000..ad87976a3 --- /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 000000000..3ed168da9 --- /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 000000000..304c38dda --- /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 000000000..f2ee08be6 --- /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 000000000..a21999298 --- /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 000000000..8cb1df013 --- /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 000000000..4b1279818 --- /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 000000000..54cf04ae9 --- /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_byte.both.c b/tests/expectations/const_generics_byte.both.c new file mode 100644 index 000000000..ccfcebc98 --- /dev/null +++ b/tests/expectations/const_generics_byte.both.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +typedef struct Parser_40__41 { + uint8_t *buf; + uintptr_t len; +} Parser_40__41; + +typedef struct Parser_123__125 { + uint8_t *buf; + uintptr_t len; +} Parser_123__125; + +void init_parens_parser(struct Parser_40__41 *p, uint8_t *buf, uintptr_t len); + +void destroy_parens_parser(struct Parser_40__41 *p); + +void init_braces_parser(struct Parser_123__125 *p, uint8_t *buf, uintptr_t len); diff --git a/tests/expectations/const_generics_byte.both.compat.c b/tests/expectations/const_generics_byte.both.compat.c new file mode 100644 index 000000000..4d15803f4 --- /dev/null +++ b/tests/expectations/const_generics_byte.both.compat.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +typedef struct Parser_40__41 { + uint8_t *buf; + uintptr_t len; +} Parser_40__41; + +typedef struct Parser_123__125 { + uint8_t *buf; + uintptr_t len; +} Parser_123__125; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void init_parens_parser(struct Parser_40__41 *p, uint8_t *buf, uintptr_t len); + +void destroy_parens_parser(struct Parser_40__41 *p); + +void init_braces_parser(struct Parser_123__125 *p, uint8_t *buf, uintptr_t len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_byte.c b/tests/expectations/const_generics_byte.c new file mode 100644 index 000000000..fc5d5ef29 --- /dev/null +++ b/tests/expectations/const_generics_byte.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +typedef struct { + uint8_t *buf; + uintptr_t len; +} Parser_40__41; + +typedef struct { + uint8_t *buf; + uintptr_t len; +} Parser_123__125; + +void init_parens_parser(Parser_40__41 *p, uint8_t *buf, uintptr_t len); + +void destroy_parens_parser(Parser_40__41 *p); + +void init_braces_parser(Parser_123__125 *p, uint8_t *buf, uintptr_t len); diff --git a/tests/expectations/const_generics_byte.compat.c b/tests/expectations/const_generics_byte.compat.c new file mode 100644 index 000000000..6cf6102d9 --- /dev/null +++ b/tests/expectations/const_generics_byte.compat.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +typedef struct { + uint8_t *buf; + uintptr_t len; +} Parser_40__41; + +typedef struct { + uint8_t *buf; + uintptr_t len; +} Parser_123__125; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void init_parens_parser(Parser_40__41 *p, uint8_t *buf, uintptr_t len); + +void destroy_parens_parser(Parser_40__41 *p); + +void init_braces_parser(Parser_123__125 *p, uint8_t *buf, uintptr_t len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_byte.cpp b/tests/expectations/const_generics_byte.cpp new file mode 100644 index 000000000..118dc98fa --- /dev/null +++ b/tests/expectations/const_generics_byte.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +template +struct Parser { + uint8_t *buf; + uintptr_t len; +}; + +extern "C" { + +void init_parens_parser(Parser<40, 41> *p, uint8_t *buf, uintptr_t len); + +void destroy_parens_parser(Parser<40, 41> *p); + +void init_braces_parser(Parser<123, 125> *p, uint8_t *buf, uintptr_t len); + +} // extern "C" diff --git a/tests/expectations/const_generics_byte.pyx b/tests/expectations/const_generics_byte.pyx new file mode 100644 index 000000000..a6099f2b9 --- /dev/null +++ b/tests/expectations/const_generics_byte.pyx @@ -0,0 +1,21 @@ +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 Parser_40__41: + uint8_t *buf; + uintptr_t len; + + ctypedef struct Parser_123__125: + uint8_t *buf; + uintptr_t len; + + void init_parens_parser(Parser_40__41 *p, uint8_t *buf, uintptr_t len); + + void destroy_parens_parser(Parser_40__41 *p); + + void init_braces_parser(Parser_123__125 *p, uint8_t *buf, uintptr_t len); diff --git a/tests/expectations/const_generics_byte.tag.c b/tests/expectations/const_generics_byte.tag.c new file mode 100644 index 000000000..4d2d5f844 --- /dev/null +++ b/tests/expectations/const_generics_byte.tag.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +struct Parser_40__41 { + uint8_t *buf; + uintptr_t len; +}; + +struct Parser_123__125 { + uint8_t *buf; + uintptr_t len; +}; + +void init_parens_parser(struct Parser_40__41 *p, uint8_t *buf, uintptr_t len); + +void destroy_parens_parser(struct Parser_40__41 *p); + +void init_braces_parser(struct Parser_123__125 *p, uint8_t *buf, uintptr_t len); diff --git a/tests/expectations/const_generics_byte.tag.compat.c b/tests/expectations/const_generics_byte.tag.compat.c new file mode 100644 index 000000000..85172fde3 --- /dev/null +++ b/tests/expectations/const_generics_byte.tag.compat.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +struct Parser_40__41 { + uint8_t *buf; + uintptr_t len; +}; + +struct Parser_123__125 { + uint8_t *buf; + uintptr_t len; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void init_parens_parser(struct Parser_40__41 *p, uint8_t *buf, uintptr_t len); + +void destroy_parens_parser(struct Parser_40__41 *p); + +void init_braces_parser(struct Parser_123__125 *p, uint8_t *buf, uintptr_t len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_byte.tag.pyx b/tests/expectations/const_generics_byte.tag.pyx new file mode 100644 index 000000000..6b91cedfc --- /dev/null +++ b/tests/expectations/const_generics_byte.tag.pyx @@ -0,0 +1,21 @@ +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 Parser_40__41: + uint8_t *buf; + uintptr_t len; + + cdef struct Parser_123__125: + uint8_t *buf; + uintptr_t len; + + void init_parens_parser(Parser_40__41 *p, uint8_t *buf, uintptr_t len); + + void destroy_parens_parser(Parser_40__41 *p); + + void init_braces_parser(Parser_123__125 *p, uint8_t *buf, uintptr_t len); diff --git a/tests/expectations/const_generics_char.both.c b/tests/expectations/const_generics_char.both.c new file mode 100644 index 000000000..4cd9041a5 --- /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 000000000..65f152ef9 --- /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 000000000..fb50a012d --- /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 000000000..7ea7ba028 --- /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 000000000..22376ccd6 --- /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 000000000..4e3bfe8dd --- /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 000000000..a6cb5ffdf --- /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 000000000..71c01fb6f --- /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 000000000..eaaa95fe6 --- /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 000000000..3047b07ba --- /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_byte.rs b/tests/rust/const_generics_byte.rs new file mode 100644 index 000000000..e150567dd --- /dev/null +++ b/tests/rust/const_generics_byte.rs @@ -0,0 +1,29 @@ +// Name mangling can cope with char-like byte literals. + +#[repr(C)] +pub struct Parser { + pub buf: *mut u8, + pub len: usize, +} + +#[no_mangle] +pub unsafe extern "C" fn init_parens_parser(p: *mut Parser, buf: *mut u8, len: usize) { + unsafe { + *p = Parser { buf, len }; + } +} + +// The same type as above, because `b'(' == 40 && b')' == 41`. And it happens +// to mangle to the same C identifier. It doesn't always work out that way! +#[no_mangle] +pub unsafe extern "C" fn destroy_parens_parser(p: *mut Parser<40, 41>) { + // nothing to do +} + + +#[no_mangle] +pub unsafe extern "C" fn init_braces_parser(p: *mut Parser, buf: *mut u8, len: usize) { + unsafe { + *p = Parser { buf, len }; + } +} diff --git a/tests/rust/const_generics_char.rs b/tests/rust/const_generics_char.rs new file mode 100644 index 000000000..85bff32fb --- /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, + } +}