From 1a34bccebc1ebf37f7242a3a48ce484af0399aba Mon Sep 17 00:00:00 2001 From: GrayJack Date: Sun, 27 Oct 2024 14:43:00 -0300 Subject: [PATCH 01/11] feat: Add support for constants defined with `if` + `cfg!` macro Cython equivalent of `#error` directive still unimplemented --- src/bindgen/ir/constant.rs | 191 +++++++++++++++++++++---- src/bindgen/language_backend/clike.rs | 13 +- src/bindgen/language_backend/cython.rs | 3 + src/bindgen/parser.rs | 40 +++--- tests/expectations/cfg.c | 36 +++++ tests/expectations/cfg.compat.c | 36 +++++ tests/expectations/cfg.cpp | 36 +++++ tests/expectations/cfg_both.c | 36 +++++ tests/expectations/cfg_both.compat.c | 36 +++++ tests/expectations/cfg_tag.c | 36 +++++ tests/expectations/cfg_tag.compat.c | 36 +++++ tests/rust/cfg.rs | 56 +++++--- 12 files changed, 490 insertions(+), 65 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index c7b7dd1a2..29d7cee3f 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,87 @@ 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(format!("Unsupported block without expression")), + }) + .ok_or(format!("Unsupported block without expression"))??; + + 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(format!("Unsupported block without expression")), + }) + .ok_or(format!("Unsupported block without expression"))??; + 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)?.into_iter(), + ), + _ => 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 +558,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(|_| format!("Unsupported `panic!` with complex message"))?; + 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 +605,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 +614,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 +806,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 +851,11 @@ impl Constant { condition.write_after(config, out); } } + +#[derive(Debug, Clone)] +pub enum PanicMacroKind { + Todo, + Unreachable, + Unimplemented, + Panic(String), +} diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index b41a3c462..05a0e4445 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 8497f3cd0..6bbf29955 100644 --- a/src/bindgen/language_backend/cython.rs +++ b/src/bindgen/language_backend/cython.rs @@ -404,6 +404,9 @@ impl LanguageBackend for CythonLanguageBackend<'_> { } write!(out, " }}"); } + Literal::PanicMacro(_) => { + warn!("SKIP: Not implemented") + } } } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 13fa3f7e4..ee3844c15 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/tests/expectations/cfg.c b/tests/expectations/cfg.c index 9285f300e..4ccc6168e 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 053c4052f..60060b931 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 d7b6250dd..5797477e4 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 uint8_t FOO_CONST = 0; +#endif + +#if defined(PLATFORM_WIN) +constexpr static const uint8_t FOO_CONST = 1; +#endif + +#if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) +constexpr static const uint8_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_both.c b/tests/expectations/cfg_both.c index 510e34e8d..6b11c1c57 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 2377824e1..3bef7bb06 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 8cc885383..fdb9ea2af 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 ec9763536..17339f7c1 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/rust/cfg.rs b/tests/rust/cfg.rs index 70893609f..1cb29a5be 100644 --- a/tests/rust/cfg.rs +++ b/tests/rust/cfg.rs @@ -1,9 +1,34 @@ +pub const FOO_CONST: u8 = 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)] From b6680e8918aa62f915cf135b1eedb08379955052 Mon Sep 17 00:00:00 2001 From: GrayJack Date: Mon, 28 Oct 2024 01:13:40 -0300 Subject: [PATCH 02/11] fix: clippy --- src/bindgen/ir/constant.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 29d7cee3f..18c84dc12 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -324,9 +324,9 @@ impl Literal { .map(|stmt| match stmt { syn::Stmt::Expr(expr, None) => Literal::load(expr), syn::Stmt::Macro(stmt_macro) => Literal::from_macro(&stmt_macro.mac), - _ => Err(format!("Unsupported block without expression")), + _ => Err("Unsupported block without expression".to_string()), }) - .ok_or(format!("Unsupported block without expression"))??; + .ok_or("Unsupported block without expression".to_string())??; vec.push((lit, Cfg::append(og_cfg, Some(cfg.clone())))); prev_cfgs.push(cfg); @@ -343,18 +343,20 @@ impl Literal { syn::Stmt::Macro(stmt_macro) => { Literal::from_macro(&stmt_macro.mac) } - _ => Err(format!("Unsupported block without expression")), + _ => { + Err("Unsupported block without expression".to_string()) + } }) - .ok_or(format!("Unsupported block without expression"))??; + .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)?.into_iter(), - ), + syn::Expr::If(_) => { + vec.extend(Literal::load_many(else_expr, og_cfg, prev_cfgs)?) + } _ => unreachable!(), } } @@ -577,7 +579,7 @@ impl Literal { } 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(|_| format!("Unsupported `panic!` with complex message"))?; + .map_err(|_| "Unsupported `panic!` with complex message".to_string())?; Ok(Literal::PanicMacro(PanicMacroKind::Panic(msg.value()))) } else { Err(format!("Unsupported macro as literal. {:?}", path)) From f34453dd625085e4a18bbcbd24d06b3e4c9ee7d2 Mon Sep 17 00:00:00 2001 From: GrayJack Date: Mon, 28 Oct 2024 02:42:07 -0300 Subject: [PATCH 03/11] chore: Update test --- tests/expectations/cfg.cpp | 6 +++--- tests/rust/cfg.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/expectations/cfg.cpp b/tests/expectations/cfg.cpp index 5797477e4..6a3b85abb 100644 --- a/tests/expectations/cfg.cpp +++ b/tests/expectations/cfg.cpp @@ -13,15 +13,15 @@ DEF M_32 = 0 #include #if defined(PLATFORM_UNIX) -constexpr static const uint8_t FOO_CONST = 0; +constexpr static const uint32_t FOO_CONST = 0; #endif #if defined(PLATFORM_WIN) -constexpr static const uint8_t FOO_CONST = 1; +constexpr static const uint32_t FOO_CONST = 1; #endif #if !(defined(PLATFORM_UNIX) || defined(PLATFORM_WIN)) -constexpr static const uint8_t FOO_CONST = 61453; +constexpr static const uint32_t FOO_CONST = 61453; #endif #if defined(PLATFORM_UNIX) diff --git a/tests/rust/cfg.rs b/tests/rust/cfg.rs index 1cb29a5be..fee4b217f 100644 --- a/tests/rust/cfg.rs +++ b/tests/rust/cfg.rs @@ -1,4 +1,4 @@ -pub const FOO_CONST: u8 = if cfg!(unix) { +pub const FOO_CONST: u32 = if cfg!(unix) { 0 } else if cfg!(windows) { 1 From d2977e8cb8e0d19375ae3b66b377ee9f0b6b594c Mon Sep 17 00:00:00 2001 From: GrayJack Date: Sun, 9 Feb 2025 05:04:10 -0300 Subject: [PATCH 04/11] feat: Raise error on Cython on panic with `if cfg!()` --- src/bindgen/language_backend/cython.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/bindgen/language_backend/cython.rs b/src/bindgen/language_backend/cython.rs index 6bbf29955..a5cb7ff0c 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,8 +405,16 @@ impl LanguageBackend for CythonLanguageBackend<'_> { } write!(out, " }}"); } - Literal::PanicMacro(_) => { - warn!("SKIP: Not implemented") + 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(")"); } } } From 03f92aff6fb48bb5dbe508f00c6a0784b3190d12 Mon Sep 17 00:00:00 2001 From: GrayJack Date: Sun, 9 Feb 2025 05:11:39 -0300 Subject: [PATCH 05/11] tests: Update cfg test output for cython --- tests/expectations/cfg.pyx | 27 +++++++++++++++++++++++++++ tests/expectations/cfg_tag.pyx | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/tests/expectations/cfg.pyx b/tests/expectations/cfg.pyx index e23fc7033..78eaa523c 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_tag.pyx b/tests/expectations/cfg_tag.pyx index e508bb30a..3d5db5ba7 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, From 68e9a52db7c37e550f220888b7e8bf7bb2a06c5c Mon Sep 17 00:00:00 2001 From: Daniil Klimov Date: Tue, 11 Feb 2025 05:59:20 +0300 Subject: [PATCH 06/11] Fixed handling of trait methods containing the unsafe attribute --- src/bindgen/utilities.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bindgen/utilities.rs b/src/bindgen/utilities.rs index 28ae78383..f40583130 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()) From 49fad17fd929166182d6c487d24180d70b4d1adf Mon Sep 17 00:00:00 2001 From: Daniil Klimov Date: Wed, 12 Feb 2025 14:11:51 +0300 Subject: [PATCH 07/11] Added tests for unsafe methotd's atributs --- .../impl_unsafe_attr_method.c.sym | 3 +++ tests/expectations/impl_unsafe_attr_method.c | 10 ++++++++++ .../impl_unsafe_attr_method.compat.c | 18 ++++++++++++++++++ tests/expectations/impl_unsafe_attr_method.cpp | 15 +++++++++++++++ tests/expectations/impl_unsafe_attr_method.pyx | 12 ++++++++++++ .../impl_unsafe_attr_method_both.c | 10 ++++++++++ .../impl_unsafe_attr_method_both.compat.c | 18 ++++++++++++++++++ .../expectations/impl_unsafe_attr_method_tag.c | 10 ++++++++++ .../impl_unsafe_attr_method_tag.compat.c | 18 ++++++++++++++++++ .../impl_unsafe_attr_method_tag.pyx | 12 ++++++++++++ tests/rust/impl_unsafe_attr_method.rs | 14 ++++++++++++++ 11 files changed, 140 insertions(+) create mode 100644 tests/expectations-symbols/impl_unsafe_attr_method.c.sym create mode 100644 tests/expectations/impl_unsafe_attr_method.c create mode 100644 tests/expectations/impl_unsafe_attr_method.compat.c create mode 100644 tests/expectations/impl_unsafe_attr_method.cpp create mode 100644 tests/expectations/impl_unsafe_attr_method.pyx create mode 100644 tests/expectations/impl_unsafe_attr_method_both.c create mode 100644 tests/expectations/impl_unsafe_attr_method_both.compat.c create mode 100644 tests/expectations/impl_unsafe_attr_method_tag.c create mode 100644 tests/expectations/impl_unsafe_attr_method_tag.compat.c create mode 100644 tests/expectations/impl_unsafe_attr_method_tag.pyx create mode 100644 tests/rust/impl_unsafe_attr_method.rs 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 000000000..6feb48ef9 --- /dev/null +++ b/tests/expectations-symbols/impl_unsafe_attr_method.c.sym @@ -0,0 +1,3 @@ +{ +new_dummy; +}; \ No newline at end of file diff --git a/tests/expectations/impl_unsafe_attr_method.c b/tests/expectations/impl_unsafe_attr_method.c new file mode 100644 index 000000000..5e9467c31 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +typedef struct { + int32_t dummy_field; +} DummyStruct; + +DummyStruct new_dummy(void); 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 000000000..26aaf31b8 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.compat.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +typedef struct { + int32_t dummy_field; +} DummyStruct; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +DummyStruct new_dummy(void); + +#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 000000000..f1e8ea90a --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include + +struct DummyStruct { + int32_t dummy_field; +}; + +extern "C" { + +DummyStruct new_dummy(); + +} // 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 000000000..0d39e71d4 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method.pyx @@ -0,0 +1,12 @@ +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(); 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 000000000..175f7f197 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_both.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +typedef struct DummyStruct { + int32_t dummy_field; +} DummyStruct; + +struct DummyStruct new_dummy(void); 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 000000000..ca5396ec3 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_both.compat.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +typedef struct DummyStruct { + int32_t dummy_field; +} DummyStruct; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct DummyStruct new_dummy(void); + +#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 000000000..31492fd51 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_tag.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +struct DummyStruct { + int32_t dummy_field; +}; + +struct DummyStruct new_dummy(void); 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 000000000..16a8962a4 --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_tag.compat.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +struct DummyStruct { + int32_t dummy_field; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct DummyStruct new_dummy(void); + +#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 000000000..2ef4bd85d --- /dev/null +++ b/tests/expectations/impl_unsafe_attr_method_tag.pyx @@ -0,0 +1,12 @@ +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(); diff --git a/tests/rust/impl_unsafe_attr_method.rs b/tests/rust/impl_unsafe_attr_method.rs new file mode 100644 index 000000000..4ab7e8c01 --- /dev/null +++ b/tests/rust/impl_unsafe_attr_method.rs @@ -0,0 +1,14 @@ +#[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, + } + } +} From 996f181dc096cab5e1fa7466a85a942d7e1fe6e7 Mon Sep 17 00:00:00 2001 From: Daniil Klimov Date: Wed, 12 Feb 2025 14:18:52 +0300 Subject: [PATCH 08/11] Added test for unsafe(no_mangle) attribute --- tests/expectations-symbols/impl_unsafe_attr_method.c.sym | 1 + tests/expectations/impl_unsafe_attr_method.c | 2 ++ tests/expectations/impl_unsafe_attr_method.compat.c | 2 ++ tests/expectations/impl_unsafe_attr_method.cpp | 2 ++ tests/expectations/impl_unsafe_attr_method.pyx | 2 ++ tests/expectations/impl_unsafe_attr_method_both.c | 2 ++ tests/expectations/impl_unsafe_attr_method_both.compat.c | 2 ++ tests/expectations/impl_unsafe_attr_method_tag.c | 2 ++ tests/expectations/impl_unsafe_attr_method_tag.compat.c | 2 ++ tests/expectations/impl_unsafe_attr_method_tag.pyx | 2 ++ tests/rust/impl_unsafe_attr_method.rs | 7 +++++++ 11 files changed, 26 insertions(+) diff --git a/tests/expectations-symbols/impl_unsafe_attr_method.c.sym b/tests/expectations-symbols/impl_unsafe_attr_method.c.sym index 6feb48ef9..271f72518 100644 --- a/tests/expectations-symbols/impl_unsafe_attr_method.c.sym +++ b/tests/expectations-symbols/impl_unsafe_attr_method.c.sym @@ -1,3 +1,4 @@ { new_dummy; +new_dummy_param; }; \ No newline at end of file diff --git a/tests/expectations/impl_unsafe_attr_method.c b/tests/expectations/impl_unsafe_attr_method.c index 5e9467c31..822c4ceab 100644 --- a/tests/expectations/impl_unsafe_attr_method.c +++ b/tests/expectations/impl_unsafe_attr_method.c @@ -8,3 +8,5 @@ typedef struct { } 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 index 26aaf31b8..a47527569 100644 --- a/tests/expectations/impl_unsafe_attr_method.compat.c +++ b/tests/expectations/impl_unsafe_attr_method.compat.c @@ -13,6 +13,8 @@ extern "C" { 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 index f1e8ea90a..1f12ee890 100644 --- a/tests/expectations/impl_unsafe_attr_method.cpp +++ b/tests/expectations/impl_unsafe_attr_method.cpp @@ -12,4 +12,6 @@ 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 index 0d39e71d4..c502b5197 100644 --- a/tests/expectations/impl_unsafe_attr_method.pyx +++ b/tests/expectations/impl_unsafe_attr_method.pyx @@ -10,3 +10,5 @@ cdef extern from *: 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 index 175f7f197..9c6a0d7d4 100644 --- a/tests/expectations/impl_unsafe_attr_method_both.c +++ b/tests/expectations/impl_unsafe_attr_method_both.c @@ -8,3 +8,5 @@ typedef struct DummyStruct { } 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 index ca5396ec3..c933e17d9 100644 --- a/tests/expectations/impl_unsafe_attr_method_both.compat.c +++ b/tests/expectations/impl_unsafe_attr_method_both.compat.c @@ -13,6 +13,8 @@ extern "C" { 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 index 31492fd51..d0db98535 100644 --- a/tests/expectations/impl_unsafe_attr_method_tag.c +++ b/tests/expectations/impl_unsafe_attr_method_tag.c @@ -8,3 +8,5 @@ struct DummyStruct { }; 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 index 16a8962a4..40e53fa85 100644 --- a/tests/expectations/impl_unsafe_attr_method_tag.compat.c +++ b/tests/expectations/impl_unsafe_attr_method_tag.compat.c @@ -13,6 +13,8 @@ extern "C" { 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 index 2ef4bd85d..23c9f172d 100644 --- a/tests/expectations/impl_unsafe_attr_method_tag.pyx +++ b/tests/expectations/impl_unsafe_attr_method_tag.pyx @@ -10,3 +10,5 @@ cdef extern from *: int32_t dummy_field; DummyStruct new_dummy(); + + DummyStruct new_dummy_param(int32_t dummy_field); diff --git a/tests/rust/impl_unsafe_attr_method.rs b/tests/rust/impl_unsafe_attr_method.rs index 4ab7e8c01..4f604bfba 100644 --- a/tests/rust/impl_unsafe_attr_method.rs +++ b/tests/rust/impl_unsafe_attr_method.rs @@ -11,4 +11,11 @@ impl DummyStruct { dummy_field: 0, } } + + #[unsafe(no_mangle)] + pub extern "C" fn new_dummy_param(dummy_field: i32) -> Self { + Self { + dummy_field, + } + } } From ccc12296c141a78c816001233a5bcbfde95c436d Mon Sep 17 00:00:00 2001 From: Daniil Klimov Date: Thu, 20 Feb 2025 04:21:12 +0300 Subject: [PATCH 09/11] Fixed error generation of structures using the keyword of as inside arrays --- src/bindgen/ir/ty.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 2d0d692ae..8e3cdb464 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -270,6 +270,14 @@ impl ConstExpr { let generic_path = GenericPath::load(&path.path)?; Ok(ConstExpr::Name(generic_path.export_name().to_owned())) } + syn::Expr::Cast(ref cast) => { + let expr = match *cast.expr { + syn::Expr::Path(ref path) => path, + _ => return Err(format!("can't handle const expression {:?}", cast)), + }; + let generic_path = GenericPath::load(&expr.path)?; + Ok(ConstExpr::Name(generic_path.export_name().to_owned())) + } _ => Err(format!("can't handle const expression {:?}", expr)), } } From cb204d73560564fc87303565f015d0f9ac3c6a74 Mon Sep 17 00:00:00 2001 From: Daniil Klimov Date: Thu, 20 Feb 2025 04:22:14 +0300 Subject: [PATCH 10/11] Added tests for as keyword inside array into structs --- tests/expectations-symbols/as_ty.c.sym | 3 +++ tests/expectations/as_ty.c | 16 ++++++++++++++++ tests/expectations/as_ty.compat.c | 24 ++++++++++++++++++++++++ tests/expectations/as_ty.cpp | 21 +++++++++++++++++++++ tests/expectations/as_ty.pyx | 17 +++++++++++++++++ tests/expectations/as_ty_both.c | 16 ++++++++++++++++ tests/expectations/as_ty_both.compat.c | 24 ++++++++++++++++++++++++ tests/expectations/as_ty_tag.c | 16 ++++++++++++++++ tests/expectations/as_ty_tag.compat.c | 24 ++++++++++++++++++++++++ tests/expectations/as_ty_tag.pyx | 17 +++++++++++++++++ tests/rust/as_ty.rs | 17 +++++++++++++++++ 11 files changed, 195 insertions(+) create mode 100644 tests/expectations-symbols/as_ty.c.sym create mode 100644 tests/expectations/as_ty.c create mode 100644 tests/expectations/as_ty.compat.c create mode 100644 tests/expectations/as_ty.cpp create mode 100644 tests/expectations/as_ty.pyx create mode 100644 tests/expectations/as_ty_both.c create mode 100644 tests/expectations/as_ty_both.compat.c create mode 100644 tests/expectations/as_ty_tag.c create mode 100644 tests/expectations/as_ty_tag.compat.c create mode 100644 tests/expectations/as_ty_tag.pyx create mode 100644 tests/rust/as_ty.rs diff --git a/tests/expectations-symbols/as_ty.c.sym b/tests/expectations-symbols/as_ty.c.sym new file mode 100644 index 000000000..84184589d --- /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/as_ty.c b/tests/expectations/as_ty.c new file mode 100644 index 000000000..9bfcc644e --- /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 000000000..b33b144cd --- /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 000000000..c5235ce30 --- /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 000000000..3da9147a3 --- /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 000000000..c30382652 --- /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 000000000..324d7210d --- /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 000000000..ebfaf4573 --- /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 000000000..744b4601a --- /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 000000000..f4df91109 --- /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/rust/as_ty.rs b/tests/rust/as_ty.rs new file mode 100644 index 000000000..db5f562e0 --- /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) { + +} From cd62410c86a34b83662638fe9a0ba481110e5f89 Mon Sep 17 00:00:00 2001 From: Daniil Klimov Date: Thu, 20 Feb 2025 14:13:23 +0300 Subject: [PATCH 11/11] The return of Cast is simplified --- src/bindgen/ir/ty.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 8e3cdb464..c5df8ae49 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -270,14 +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) => { - let expr = match *cast.expr { - syn::Expr::Path(ref path) => path, - _ => return Err(format!("can't handle const expression {:?}", cast)), - }; - let generic_path = GenericPath::load(&expr.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)), } }