diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index c7b7dd1a..18c84dc1 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -107,6 +107,7 @@ pub enum Literal { ty: Type, value: Box, }, + PanicMacro(PanicMacroKind), } impl Literal { @@ -156,6 +157,7 @@ impl Literal { } } Literal::Expr(..) => {} + Literal::PanicMacro(_) => {} } } @@ -181,6 +183,7 @@ impl Literal { Literal::FieldAccess { ref base, .. } => base.is_valid(bindings), Literal::Struct { ref path, .. } => bindings.struct_exists(path), Literal::Cast { ref value, .. } => value.is_valid(bindings), + Literal::PanicMacro(_) => true, } } @@ -210,6 +213,7 @@ impl Literal { true } Literal::Cast { ref value, .. } => value.visit(visitor), + Literal::PanicMacro(_) => true, } } @@ -285,9 +289,89 @@ impl Literal { ty.rename_for_config(config, &GenericParams::default()); value.rename_for_config(config); } + Literal::PanicMacro(_) => {} } } + // Handles `if` expressions with `cfg!` macros + pub fn load_many( + expr: &syn::Expr, + og_cfg: Option<&Cfg>, + prev_cfgs: &mut Vec, + ) -> Result)>, String> { + let mut vec = Vec::new(); + match *expr { + syn::Expr::If(syn::ExprIf { + ref cond, + ref then_branch, + ref else_branch, + .. + }) => match cond.as_ref() { + syn::Expr::Macro(syn::ExprMacro { mac, .. }) => { + if !mac.path.is_ident("cfg") { + return Err(format!( + "Unsupported if expression with macro {:?}", + mac.path + )); + } + + let cfg: Cfg = + syn::parse2(mac.tokens.clone()).map_err(|err| err.to_string())?; + + let lit = then_branch + .stmts + .last() + .map(|stmt| match stmt { + syn::Stmt::Expr(expr, None) => Literal::load(expr), + syn::Stmt::Macro(stmt_macro) => Literal::from_macro(&stmt_macro.mac), + _ => Err("Unsupported block without expression".to_string()), + }) + .ok_or("Unsupported block without expression".to_string())??; + + vec.push((lit, Cfg::append(og_cfg, Some(cfg.clone())))); + prev_cfgs.push(cfg); + + if let Some((_, else_expr)) = else_branch { + match else_expr.as_ref() { + syn::Expr::Block(expr_block) => { + let lit = expr_block + .block + .stmts + .last() + .map(|stmt| match stmt { + syn::Stmt::Expr(expr, None) => Literal::load(expr), + syn::Stmt::Macro(stmt_macro) => { + Literal::from_macro(&stmt_macro.mac) + } + _ => { + Err("Unsupported block without expression".to_string()) + } + }) + .ok_or("Unsupported block without expression".to_string())??; + let cfg = Cfg::append( + og_cfg, + Some(Cfg::Not(Box::new(Cfg::Any(prev_cfgs.clone())))), + ); + vec.push((lit, cfg)); + } + syn::Expr::If(_) => { + vec.extend(Literal::load_many(else_expr, og_cfg, prev_cfgs)?) + } + _ => unreachable!(), + } + } + } + _ => return Err(format!("Unsupported if expression. {:?}", *expr)), + }, + _ => { + let lit = Literal::load(expr)?; + let cfg = Cfg::append(og_cfg, None); + vec.push((lit, cfg)); + } + } + Ok(vec) + } + // Translate from full blown `syn::Expr` into a simpler `Literal` type pub fn load(expr: &syn::Expr) -> Result { match *expr { @@ -476,11 +560,33 @@ impl Literal { } } + syn::Expr::Macro(syn::ExprMacro { ref mac, .. }) => Literal::from_macro(mac), _ => Err(format!("Unsupported expression. {:?}", *expr)), } } } +impl Literal { + fn from_macro(mac: &syn::Macro) -> Result { + let path = &mac.path; + let tokens = &mac.tokens; + if path.is_ident("todo") { + Ok(Literal::PanicMacro(PanicMacroKind::Todo)) + } else if path.is_ident("unreachable") { + Ok(Literal::PanicMacro(PanicMacroKind::Unreachable)) + } else if path.is_ident("unimplemented") { + Ok(Literal::PanicMacro(PanicMacroKind::Unimplemented)) + } else if path.is_ident("panic") { + // We only support simple messages, i.e. string literals + let msg: syn::LitStr = syn::parse2(tokens.clone()) + .map_err(|_| "Unsupported `panic!` with complex message".to_string())?; + Ok(Literal::PanicMacro(PanicMacroKind::Panic(msg.value()))) + } else { + Err(format!("Unsupported macro as literal. {:?}", path)) + } + } +} + #[derive(Debug, Clone)] pub struct Constant { pub path: Path, @@ -501,7 +607,7 @@ impl Constant { expr: &syn::Expr, attrs: &[syn::Attribute], associated_to: Option, - ) -> Result { + ) -> Result, String> { let ty = Type::load(ty)?; let mut ty = match ty { Some(ty) => ty, @@ -510,22 +616,34 @@ impl Constant { } }; - let mut lit = Literal::load(expr)?; - if let Some(ref associated_to) = associated_to { ty.replace_self_with(associated_to); - lit.replace_self_with(associated_to); } - Ok(Constant::new( - path, - ty, - lit, - Cfg::append(mod_cfg, Cfg::load(attrs)), - AnnotationSet::load(attrs)?, - Documentation::load(attrs), - associated_to, - )) + let og_cfg = Cfg::append(mod_cfg, Cfg::load(attrs)); + + let mut prev_cfgs = Vec::new(); + let lits = Literal::load_many(expr, og_cfg.as_ref(), &mut prev_cfgs)?; + + let mut consts = Vec::with_capacity(lits.len()); + + for (mut lit, cfg) in lits { + if let Some(ref associated_to) = associated_to { + lit.replace_self_with(associated_to); + } + + consts.push(Constant::new( + path.clone(), + ty.clone(), + lit, + cfg, + AnnotationSet::load(attrs)?, + Documentation::load(attrs), + associated_to.clone(), + )); + } + + Ok(consts) } pub fn new( @@ -690,27 +808,36 @@ impl Constant { let allow_constexpr = config.constant.allow_constexpr && self.value.can_be_constexpr(); match config.language { Language::Cxx if config.constant.allow_static_const || allow_constexpr => { - if allow_constexpr { - out.write("constexpr ") - } + if matches!(self.value, Literal::PanicMacro(_)) { + write!(out, "#error "); + language_backend.write_literal(out, value); + } else { + if allow_constexpr { + out.write("constexpr ") + } - if config.constant.allow_static_const { - out.write(if in_body { "inline " } else { "static " }); - } + if config.constant.allow_static_const { + out.write(if in_body { "inline " } else { "static " }); + } - if let Type::Ptr { is_const: true, .. } = self.ty { - // Nothing. - } else { - out.write("const "); - } + if let Type::Ptr { is_const: true, .. } = self.ty { + // Nothing. + } else { + out.write("const "); + } - language_backend.write_type(out, &self.ty); - write!(out, " {} = ", name); - language_backend.write_literal(out, value); - write!(out, ";"); + language_backend.write_type(out, &self.ty); + write!(out, " {} = ", name); + language_backend.write_literal(out, value); + write!(out, ";"); + } } Language::Cxx | Language::C => { - write!(out, "#define {} ", name); + if matches!(self.value, Literal::PanicMacro(_)) { + write!(out, "#error "); + } else { + write!(out, "#define {} ", name); + } language_backend.write_literal(out, value); } Language::Cython => { @@ -726,3 +853,11 @@ impl Constant { condition.write_after(config, out); } } + +#[derive(Debug, Clone)] +pub enum PanicMacroKind { + Todo, + Unreachable, + Unimplemented, + Panic(String), +} diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 2d0d692a..c5df8ae4 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -270,6 +270,7 @@ impl ConstExpr { let generic_path = GenericPath::load(&path.path)?; Ok(ConstExpr::Name(generic_path.export_name().to_owned())) } + syn::Expr::Cast(ref cast) => Ok(ConstExpr::load(&cast.expr)?), _ => Err(format!("can't handle const expression {:?}", expr)), } } diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index b41a3c46..05a0e444 100644 --- a/src/bindgen/language_backend/clike.rs +++ b/src/bindgen/language_backend/clike.rs @@ -1,7 +1,7 @@ use crate::bindgen::ir::{ to_known_assoc_constant, ConditionWrite, DeprecatedNoteKind, Documentation, Enum, EnumVariant, - Field, GenericParams, Item, Literal, OpaqueItem, ReprAlign, Static, Struct, ToCondition, Type, - Typedef, Union, + Field, GenericParams, Item, Literal, OpaqueItem, PanicMacroKind, ReprAlign, Static, Struct, + ToCondition, Type, Typedef, Union, }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::rename::IdentifierType; @@ -949,6 +949,15 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { } write!(out, "}}"); } + Literal::PanicMacro(panic_macro_kind) => { + match panic_macro_kind { + PanicMacroKind::Todo => write!(out, r#""not yet implemented""#), + PanicMacroKind::Unreachable => write!(out, r#""reached unreachable code""#), + PanicMacroKind::Unimplemented => write!(out, r#""not implemented""#), + // Debug print of &str and String already add the `"` + PanicMacroKind::Panic(msg) => write!(out, "{:?}", msg), + } + } } } diff --git a/src/bindgen/language_backend/cython.rs b/src/bindgen/language_backend/cython.rs index 8497f3cd..a5cb7ff0 100644 --- a/src/bindgen/language_backend/cython.rs +++ b/src/bindgen/language_backend/cython.rs @@ -1,6 +1,7 @@ use crate::bindgen::ir::{ to_known_assoc_constant, ConditionWrite, DeprecatedNoteKind, Documentation, Enum, EnumVariant, - Field, Item, Literal, OpaqueItem, ReprAlign, Static, Struct, ToCondition, Type, Typedef, Union, + Field, Item, Literal, OpaqueItem, PanicMacroKind, ReprAlign, Static, Struct, ToCondition, Type, + Typedef, Union, }; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::writer::{ListType, SourceWriter}; @@ -404,6 +405,17 @@ impl LanguageBackend for CythonLanguageBackend<'_> { } write!(out, " }}"); } + Literal::PanicMacro(kind) => { + out.write("raise TypeError("); + match kind { + PanicMacroKind::Todo => write!(out, r#""not yet implemented""#), + PanicMacroKind::Unreachable => write!(out, r#""reached unreachable code""#), + PanicMacroKind::Unimplemented => write!(out, r#""not implemented""#), + // Debug print of &str and String already add the `"` + PanicMacroKind::Panic(msg) => write!(out, "{:?}", msg), + } + out.write(")"); + } } } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 13fa3f7e..ee3844c1 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -807,20 +807,23 @@ impl Parse { &item.attrs, Some(impl_path.clone()), ) { - Ok(constant) => { + Ok(constants) => { info!("Take {}::{}::{}.", crate_name, impl_path, &item.ident); - let mut any = false; - self.structs.for_items_mut(&impl_path, |item| { - any = true; - item.add_associated_constant(constant.clone()); - }); - // Handle associated constants to other item types that are - // not structs like enums or such as regular constants. - if !any && !self.constants.try_insert(constant) { - error!( - "Conflicting name for constant {}::{}::{}.", - crate_name, impl_path, &item.ident, - ); + + for constant in constants { + let mut any = false; + self.structs.for_items_mut(&impl_path, |item| { + any = true; + item.add_associated_constant(constant.clone()); + }); + // Handle associated constants to other item types that are + // not structs like enums or such as regular constants. + if !any && !self.constants.try_insert(constant) { + error!( + "Conflicting name for constant {}::{}::{}.", + crate_name, impl_path, &item.ident, + ); + } } } Err(msg) => { @@ -858,12 +861,13 @@ impl Parse { let path = Path::new(item.ident.unraw().to_string()); match Constant::load(path, mod_cfg, &item.ty, &item.expr, &item.attrs, None) { - Ok(constant) => { + Ok(constants) => { info!("Take {}::{}.", crate_name, &item.ident); - - let full_name = constant.path.clone(); - if !self.constants.try_insert(constant) { - error!("Conflicting name for constant {}", full_name); + for constant in constants { + let full_name = constant.path.clone(); + if !self.constants.try_insert(constant) { + error!("Conflicting name for constant {}", full_name); + } } } Err(msg) => { diff --git a/src/bindgen/utilities.rs b/src/bindgen/utilities.rs index 28ae7838..f4058313 100644 --- a/src/bindgen/utilities.rs +++ b/src/bindgen/utilities.rs @@ -50,6 +50,7 @@ impl SynItemHelpers for syn::ImplItemFn { fn exported_name(&self) -> Option { self.attrs .attr_name_value_lookup("export_name") + .or_else(|| self.unsafe_attr_name_value_lookup("export_name")) .or_else(|| { if self.is_no_mangle() { Some(self.sig.ident.unraw().to_string()) diff --git a/tests/expectations-symbols/as_ty.c.sym b/tests/expectations-symbols/as_ty.c.sym new file mode 100644 index 00000000..84184589 --- /dev/null +++ b/tests/expectations-symbols/as_ty.c.sym @@ -0,0 +1,3 @@ +{ +some_fn; +}; \ No newline at end of file diff --git a/tests/expectations-symbols/impl_unsafe_attr_method.c.sym b/tests/expectations-symbols/impl_unsafe_attr_method.c.sym new file mode 100644 index 00000000..271f7251 --- /dev/null +++ b/tests/expectations-symbols/impl_unsafe_attr_method.c.sym @@ -0,0 +1,4 @@ +{ +new_dummy; +new_dummy_param; +}; \ No newline at end of file diff --git a/tests/expectations/as_ty.c b/tests/expectations/as_ty.c new file mode 100644 index 00000000..9bfcc644 --- /dev/null +++ b/tests/expectations/as_ty.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#define SIZE 4 + +typedef struct { + uint32_t items[SIZE]; +} WithoutAs; + +typedef struct { + uint32_t items[SIZE]; +} WithAs; + +void some_fn(WithoutAs a, WithAs b); diff --git a/tests/expectations/as_ty.compat.c b/tests/expectations/as_ty.compat.c new file mode 100644 index 00000000..b33b144c --- /dev/null +++ b/tests/expectations/as_ty.compat.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +#define SIZE 4 + +typedef struct { + uint32_t items[SIZE]; +} WithoutAs; + +typedef struct { + uint32_t items[SIZE]; +} WithAs; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void some_fn(WithoutAs a, WithAs b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/as_ty.cpp b/tests/expectations/as_ty.cpp new file mode 100644 index 00000000..c5235ce3 --- /dev/null +++ b/tests/expectations/as_ty.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +constexpr static const intptr_t SIZE = 4; + +struct WithoutAs { + uint32_t items[SIZE]; +}; + +struct WithAs { + uint32_t items[SIZE]; +}; + +extern "C" { + +void some_fn(WithoutAs a, WithAs b); + +} // extern "C" diff --git a/tests/expectations/as_ty.pyx b/tests/expectations/as_ty.pyx new file mode 100644 index 00000000..3da9147a --- /dev/null +++ b/tests/expectations/as_ty.pyx @@ -0,0 +1,17 @@ +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 *: + + const intptr_t SIZE # = 4 + + ctypedef struct WithoutAs: + uint32_t items[SIZE]; + + ctypedef struct WithAs: + uint32_t items[SIZE]; + + void some_fn(WithoutAs a, WithAs b); diff --git a/tests/expectations/as_ty_both.c b/tests/expectations/as_ty_both.c new file mode 100644 index 00000000..c3038265 --- /dev/null +++ b/tests/expectations/as_ty_both.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#define SIZE 4 + +typedef struct WithoutAs { + uint32_t items[SIZE]; +} WithoutAs; + +typedef struct WithAs { + uint32_t items[SIZE]; +} WithAs; + +void some_fn(struct WithoutAs a, struct WithAs b); diff --git a/tests/expectations/as_ty_both.compat.c b/tests/expectations/as_ty_both.compat.c new file mode 100644 index 00000000..324d7210 --- /dev/null +++ b/tests/expectations/as_ty_both.compat.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +#define SIZE 4 + +typedef struct WithoutAs { + uint32_t items[SIZE]; +} WithoutAs; + +typedef struct WithAs { + uint32_t items[SIZE]; +} WithAs; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void some_fn(struct WithoutAs a, struct WithAs b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/as_ty_tag.c b/tests/expectations/as_ty_tag.c new file mode 100644 index 00000000..ebfaf457 --- /dev/null +++ b/tests/expectations/as_ty_tag.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#define SIZE 4 + +struct WithoutAs { + uint32_t items[SIZE]; +}; + +struct WithAs { + uint32_t items[SIZE]; +}; + +void some_fn(struct WithoutAs a, struct WithAs b); diff --git a/tests/expectations/as_ty_tag.compat.c b/tests/expectations/as_ty_tag.compat.c new file mode 100644 index 00000000..744b4601 --- /dev/null +++ b/tests/expectations/as_ty_tag.compat.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +#define SIZE 4 + +struct WithoutAs { + uint32_t items[SIZE]; +}; + +struct WithAs { + uint32_t items[SIZE]; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void some_fn(struct WithoutAs a, struct WithAs b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/as_ty_tag.pyx b/tests/expectations/as_ty_tag.pyx new file mode 100644 index 00000000..f4df9110 --- /dev/null +++ b/tests/expectations/as_ty_tag.pyx @@ -0,0 +1,17 @@ +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 *: + + const intptr_t SIZE # = 4 + + cdef struct WithoutAs: + uint32_t items[SIZE]; + + cdef struct WithAs: + uint32_t items[SIZE]; + + void some_fn(WithoutAs a, WithAs b); diff --git a/tests/expectations/cfg.c b/tests/expectations/cfg.c index 9285f300..4ccc6168 100644 --- a/tests/expectations/cfg.c +++ b/tests/expectations/cfg.c @@ -11,6 +11,42 @@ DEF M_32 = 0 #include #include +#if defined(PLATFORM_UNIX) +#define FOO_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#define FOO_CONST 1 +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define FOO_CONST 61453 +#endif + +#if defined(PLATFORM_UNIX) +#define BAR_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#error "reached unreachable code" +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define BAR_CONST 1 +#endif + +#if (defined(X11) && defined(PLATFORM_UNIX)) +#define BAZ_CONST 0 +#endif + +#if (defined(X11) && defined(PLATFORM_WIN)) +#define BAZ_CONST 1 +#endif + +#if (defined(X11) && !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN))) +#error "Baz error" +#endif + #if (defined(PLATFORM_WIN) || defined(M_32)) enum BarType { A, diff --git a/tests/expectations/cfg.compat.c b/tests/expectations/cfg.compat.c index 053c4052..60060b93 100644 --- a/tests/expectations/cfg.compat.c +++ b/tests/expectations/cfg.compat.c @@ -11,6 +11,42 @@ DEF M_32 = 0 #include #include +#if defined(PLATFORM_UNIX) +#define FOO_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#define FOO_CONST 1 +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define FOO_CONST 61453 +#endif + +#if defined(PLATFORM_UNIX) +#define BAR_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#error "reached unreachable code" +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define BAR_CONST 1 +#endif + +#if (defined(X11) && defined(PLATFORM_UNIX)) +#define BAZ_CONST 0 +#endif + +#if (defined(X11) && defined(PLATFORM_WIN)) +#define BAZ_CONST 1 +#endif + +#if (defined(X11) && !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN))) +#error "Baz error" +#endif + #if (defined(PLATFORM_WIN) || defined(M_32)) enum BarType #ifdef __cplusplus diff --git a/tests/expectations/cfg.cpp b/tests/expectations/cfg.cpp index d7b6250d..6a3b85ab 100644 --- a/tests/expectations/cfg.cpp +++ b/tests/expectations/cfg.cpp @@ -12,6 +12,42 @@ DEF M_32 = 0 #include #include +#if defined(PLATFORM_UNIX) +constexpr static const uint32_t FOO_CONST = 0; +#endif + +#if defined(PLATFORM_WIN) +constexpr static const uint32_t FOO_CONST = 1; +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +constexpr static const uint32_t FOO_CONST = 61453; +#endif + +#if defined(PLATFORM_UNIX) +constexpr static const uint8_t BAR_CONST = 0; +#endif + +#if defined(PLATFORM_WIN) +#error "reached unreachable code" +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +constexpr static const uint8_t BAR_CONST = 1; +#endif + +#if (defined(X11) && defined(PLATFORM_UNIX)) +constexpr static const uint8_t BAZ_CONST = 0; +#endif + +#if (defined(X11) && defined(PLATFORM_WIN)) +constexpr static const uint8_t BAZ_CONST = 1; +#endif + +#if (defined(X11) && !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN))) +#error "Baz error" +#endif + #if (defined(PLATFORM_WIN) || defined(M_32)) enum class BarType : uint32_t { A, diff --git a/tests/expectations/cfg.pyx b/tests/expectations/cfg.pyx index e23fc703..78eaa523 100644 --- a/tests/expectations/cfg.pyx +++ b/tests/expectations/cfg.pyx @@ -14,6 +14,33 @@ cdef extern from *: cdef extern from *: + IF PLATFORM_UNIX: + const uint32_t FOO_CONST # = 0 + + IF PLATFORM_WIN: + const uint32_t FOO_CONST # = 1 + + IF not (PLATFORM_UNIX or PLATFORM_WIN): + const uint32_t FOO_CONST # = 61453 + + IF PLATFORM_UNIX: + const uint8_t BAR_CONST # = 0 + + IF PLATFORM_WIN: + const uint8_t BAR_CONST # = raise TypeError("reached unreachable code") + + IF not (PLATFORM_UNIX or PLATFORM_WIN): + const uint8_t BAR_CONST # = 1 + + IF (X11 and PLATFORM_UNIX): + const uint8_t BAZ_CONST # = 0 + + IF (X11 and PLATFORM_WIN): + const uint8_t BAZ_CONST # = 1 + + IF (X11 and not (PLATFORM_UNIX or PLATFORM_WIN)): + const uint8_t BAZ_CONST # = raise TypeError("Baz error") + IF (PLATFORM_WIN or M_32): cdef enum: A, diff --git a/tests/expectations/cfg_both.c b/tests/expectations/cfg_both.c index 510e34e8..6b11c1c5 100644 --- a/tests/expectations/cfg_both.c +++ b/tests/expectations/cfg_both.c @@ -11,6 +11,42 @@ DEF M_32 = 0 #include #include +#if defined(PLATFORM_UNIX) +#define FOO_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#define FOO_CONST 1 +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define FOO_CONST 61453 +#endif + +#if defined(PLATFORM_UNIX) +#define BAR_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#error "reached unreachable code" +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define BAR_CONST 1 +#endif + +#if (defined(X11) && defined(PLATFORM_UNIX)) +#define BAZ_CONST 0 +#endif + +#if (defined(X11) && defined(PLATFORM_WIN)) +#define BAZ_CONST 1 +#endif + +#if (defined(X11) && !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN))) +#error "Baz error" +#endif + #if (defined(PLATFORM_WIN) || defined(M_32)) enum BarType { A, diff --git a/tests/expectations/cfg_both.compat.c b/tests/expectations/cfg_both.compat.c index 2377824e..3bef7bb0 100644 --- a/tests/expectations/cfg_both.compat.c +++ b/tests/expectations/cfg_both.compat.c @@ -11,6 +11,42 @@ DEF M_32 = 0 #include #include +#if defined(PLATFORM_UNIX) +#define FOO_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#define FOO_CONST 1 +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define FOO_CONST 61453 +#endif + +#if defined(PLATFORM_UNIX) +#define BAR_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#error "reached unreachable code" +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define BAR_CONST 1 +#endif + +#if (defined(X11) && defined(PLATFORM_UNIX)) +#define BAZ_CONST 0 +#endif + +#if (defined(X11) && defined(PLATFORM_WIN)) +#define BAZ_CONST 1 +#endif + +#if (defined(X11) && !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN))) +#error "Baz error" +#endif + #if (defined(PLATFORM_WIN) || defined(M_32)) enum BarType #ifdef __cplusplus diff --git a/tests/expectations/cfg_tag.c b/tests/expectations/cfg_tag.c index 8cc88538..fdb9ea2a 100644 --- a/tests/expectations/cfg_tag.c +++ b/tests/expectations/cfg_tag.c @@ -11,6 +11,42 @@ DEF M_32 = 0 #include #include +#if defined(PLATFORM_UNIX) +#define FOO_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#define FOO_CONST 1 +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define FOO_CONST 61453 +#endif + +#if defined(PLATFORM_UNIX) +#define BAR_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#error "reached unreachable code" +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define BAR_CONST 1 +#endif + +#if (defined(X11) && defined(PLATFORM_UNIX)) +#define BAZ_CONST 0 +#endif + +#if (defined(X11) && defined(PLATFORM_WIN)) +#define BAZ_CONST 1 +#endif + +#if (defined(X11) && !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN))) +#error "Baz error" +#endif + #if (defined(PLATFORM_WIN) || defined(M_32)) enum BarType { A, diff --git a/tests/expectations/cfg_tag.compat.c b/tests/expectations/cfg_tag.compat.c index ec976353..17339f7c 100644 --- a/tests/expectations/cfg_tag.compat.c +++ b/tests/expectations/cfg_tag.compat.c @@ -11,6 +11,42 @@ DEF M_32 = 0 #include #include +#if defined(PLATFORM_UNIX) +#define FOO_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#define FOO_CONST 1 +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define FOO_CONST 61453 +#endif + +#if defined(PLATFORM_UNIX) +#define BAR_CONST 0 +#endif + +#if defined(PLATFORM_WIN) +#error "reached unreachable code" +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +#define BAR_CONST 1 +#endif + +#if (defined(X11) && defined(PLATFORM_UNIX)) +#define BAZ_CONST 0 +#endif + +#if (defined(X11) && defined(PLATFORM_WIN)) +#define BAZ_CONST 1 +#endif + +#if (defined(X11) && !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN))) +#error "Baz error" +#endif + #if (defined(PLATFORM_WIN) || defined(M_32)) enum BarType #ifdef __cplusplus diff --git a/tests/expectations/cfg_tag.pyx b/tests/expectations/cfg_tag.pyx index e508bb30..3d5db5ba 100644 --- a/tests/expectations/cfg_tag.pyx +++ b/tests/expectations/cfg_tag.pyx @@ -14,6 +14,33 @@ cdef extern from *: cdef extern from *: + IF PLATFORM_UNIX: + const uint32_t FOO_CONST # = 0 + + IF PLATFORM_WIN: + const uint32_t FOO_CONST # = 1 + + IF not (PLATFORM_UNIX or PLATFORM_WIN): + const uint32_t FOO_CONST # = 61453 + + IF PLATFORM_UNIX: + const uint8_t BAR_CONST # = 0 + + IF PLATFORM_WIN: + const uint8_t BAR_CONST # = raise TypeError("reached unreachable code") + + IF not (PLATFORM_UNIX or PLATFORM_WIN): + const uint8_t BAR_CONST # = 1 + + IF (X11 and PLATFORM_UNIX): + const uint8_t BAZ_CONST # = 0 + + IF (X11 and PLATFORM_WIN): + const uint8_t BAZ_CONST # = 1 + + IF (X11 and not (PLATFORM_UNIX or PLATFORM_WIN)): + const uint8_t BAZ_CONST # = raise TypeError("Baz error") + IF (PLATFORM_WIN or M_32): cdef enum: A, diff --git a/tests/expectations/impl_unsafe_attr_method.c b/tests/expectations/impl_unsafe_attr_method.c new file mode 100644 index 00000000..822c4cea --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +typedef struct { + int32_t dummy_field; +} DummyStruct; + +DummyStruct new_dummy(void); + +DummyStruct new_dummy_param(int32_t dummy_field); diff --git a/tests/expectations/impl_unsafe_attr_method.compat.c b/tests/expectations/impl_unsafe_attr_method.compat.c new file mode 100644 index 00000000..a4752756 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +typedef struct { + int32_t dummy_field; +} DummyStruct; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +DummyStruct new_dummy(void); + +DummyStruct new_dummy_param(int32_t dummy_field); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/impl_unsafe_attr_method.cpp b/tests/expectations/impl_unsafe_attr_method.cpp new file mode 100644 index 00000000..1f12ee89 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include + +struct DummyStruct { + int32_t dummy_field; +}; + +extern "C" { + +DummyStruct new_dummy(); + +DummyStruct new_dummy_param(int32_t dummy_field); + +} // extern "C" diff --git a/tests/expectations/impl_unsafe_attr_method.pyx b/tests/expectations/impl_unsafe_attr_method.pyx new file mode 100644 index 00000000..c502b519 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.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 DummyStruct: + int32_t dummy_field; + + DummyStruct new_dummy(); + + DummyStruct new_dummy_param(int32_t dummy_field); diff --git a/tests/expectations/impl_unsafe_attr_method_both.c b/tests/expectations/impl_unsafe_attr_method_both.c new file mode 100644 index 00000000..9c6a0d7d --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_both.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +typedef struct DummyStruct { + int32_t dummy_field; +} DummyStruct; + +struct DummyStruct new_dummy(void); + +struct DummyStruct new_dummy_param(int32_t dummy_field); diff --git a/tests/expectations/impl_unsafe_attr_method_both.compat.c b/tests/expectations/impl_unsafe_attr_method_both.compat.c new file mode 100644 index 00000000..c933e17d --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_both.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +typedef struct DummyStruct { + int32_t dummy_field; +} DummyStruct; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct DummyStruct new_dummy(void); + +struct DummyStruct new_dummy_param(int32_t dummy_field); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/impl_unsafe_attr_method_tag.c b/tests/expectations/impl_unsafe_attr_method_tag.c new file mode 100644 index 00000000..d0db9853 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_tag.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +struct DummyStruct { + int32_t dummy_field; +}; + +struct DummyStruct new_dummy(void); + +struct DummyStruct new_dummy_param(int32_t dummy_field); diff --git a/tests/expectations/impl_unsafe_attr_method_tag.compat.c b/tests/expectations/impl_unsafe_attr_method_tag.compat.c new file mode 100644 index 00000000..40e53fa8 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_tag.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +struct DummyStruct { + int32_t dummy_field; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct DummyStruct new_dummy(void); + +struct DummyStruct new_dummy_param(int32_t dummy_field); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/impl_unsafe_attr_method_tag.pyx b/tests/expectations/impl_unsafe_attr_method_tag.pyx new file mode 100644 index 00000000..23c9f172 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_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 DummyStruct: + int32_t dummy_field; + + DummyStruct new_dummy(); + + DummyStruct new_dummy_param(int32_t dummy_field); diff --git a/tests/rust/as_ty.rs b/tests/rust/as_ty.rs new file mode 100644 index 00000000..db5f562e --- /dev/null +++ b/tests/rust/as_ty.rs @@ -0,0 +1,17 @@ +pub const SIZE: isize = 4; + +#[repr(C)] +pub struct WithoutAs { + items: [char; SIZE as usize], +} + +#[repr(C)] +pub struct WithAs { + items: [char; SIZE as usize], +} + +// dummy function to make `WithoutAs` and `WithAs` part of the public api +#[no_mangle] +pub extern fn some_fn(a: WithoutAs, b: WithAs) { + +} diff --git a/tests/rust/cfg.rs b/tests/rust/cfg.rs index 70893609..fee4b217 100644 --- a/tests/rust/cfg.rs +++ b/tests/rust/cfg.rs @@ -1,9 +1,34 @@ +pub const FOO_CONST: u32 = if cfg!(unix) { + 0 +} else if cfg!(windows) { + 1 +} else { + 0xF00D +}; + +pub const BAR_CONST: u8 = if cfg!(unix) { + 0 +} else if cfg!(windows) { + unreachable!() +} else { + 1 +}; + +#[cfg(x11)] +pub const BAZ_CONST: u8 = if cfg!(unix) { + 0 +} else if cfg!(windows) { + 1 +} else { + panic!("Baz error") +}; + #[cfg(all(unix, x11))] #[repr(u32)] enum FooType { - A, - B, - C, + A, + B, + C, } #[cfg(all(unix, x11))] @@ -14,12 +39,12 @@ struct FooHandle { y: f32, } -#[cfg(any(windows, target_pointer_width="32"))] +#[cfg(any(windows, target_pointer_width = "32"))] #[repr(u32)] enum BarType { - A, - B, - C, + A, + B, + C, } #[repr(u8)] @@ -29,10 +54,12 @@ pub enum C { #[cfg(windows)] C3, #[cfg(unix)] - C5 { int: i32 }, + C5 { + int: i32, + }, } -#[cfg(any(windows, target_pointer_width="32"))] +#[cfg(any(windows, target_pointer_width = "32"))] #[repr(C)] struct BarHandle { ty: BarType, @@ -51,17 +78,14 @@ struct ConditionalField { #[cfg(all(unix, x11))] #[no_mangle] -pub extern "C" fn root(a: FooHandle, c: C) -{ } +pub extern "C" fn root(a: FooHandle, c: C) {} -#[cfg(any(windows, target_pointer_width="32"))] +#[cfg(any(windows, target_pointer_width = "32"))] #[no_mangle] -pub extern "C" fn root(a: BarHandle, c: C) -{ } +pub extern "C" fn root(a: BarHandle, c: C) {} #[no_mangle] -pub extern "C" fn cond(a: ConditionalField) -{ } +pub extern "C" fn cond(a: ConditionalField) {} // src/lib.rs #[repr(C)] diff --git a/tests/rust/impl_unsafe_attr_method.rs b/tests/rust/impl_unsafe_attr_method.rs new file mode 100644 index 00000000..4f604bfb --- /dev/null +++ b/tests/rust/impl_unsafe_attr_method.rs @@ -0,0 +1,21 @@ +#[repr(C)] +pub struct DummyStruct { + dummy_field: i32, +} + + +impl DummyStruct { + #[unsafe(export_name = "new_dummy")] + pub const extern "C" fn new() -> Self { + Self { + dummy_field: 0, + } + } + + #[unsafe(no_mangle)] + pub extern "C" fn new_dummy_param(dummy_field: i32) -> Self { + Self { + dummy_field, + } + } +}