1use std::collections::{HashMap, HashSet};
6use std::io::{self, Write};
7
8use crate::ast::{AssertKind, AssignOp, BinOp, BlockItem, CompoundStmt, Declaration, DeclSpecs, DerivedDecl, Expr, ExprKind, ForInit, FunctionDef, Initializer, ParamDecl, Stmt, TypeSpec};
9
10use crate::intern::InternedStr;
11use crate::enum_dict::EnumDict;
12use crate::infer_api::InferResult;
13use crate::intern::StringInterner;
14use crate::macro_infer::{MacroInferContext, MacroInferInfo, MacroParam, ParseResult};
15use crate::rust_decl::RustDeclDict;
16use crate::syn_codegen::normalize_parens;
17use crate::unified_type::UnifiedType;
18use crate::sexp::SexpPrinter;
19
20#[derive(Debug, Default, Clone)]
22pub struct BindingsInfo {
23 pub static_arrays: HashSet<String>,
25 pub static_types: HashMap<String, String>,
28 pub bitfield_methods: HashMap<String, HashSet<String>>,
30}
31
32impl BindingsInfo {
33 pub fn from_rust_decl_dict(dict: &RustDeclDict) -> Self {
35 Self {
36 static_arrays: dict.static_arrays.clone(),
37 static_types: dict.static_types.clone(),
38 bitfield_methods: dict.bitfield_methods.clone(),
39 }
40 }
41
42 pub fn static_array_element_type(&self, name: &str) -> Option<String> {
46 let ty = self.static_types.get(name)?;
47 let s = ty.trim();
48 let s = s.strip_prefix('[')?;
49 let s = s.strip_suffix(']')?;
50 let semi = s.rfind(';')?;
51 Some(s[..semi].trim().to_string())
52 }
53}
54
55const LIBC_FUNCTIONS: &[&str] = &[
59 "strcmp", "strlen", "strncmp", "strcpy", "strncpy",
60 "memset", "memchr", "memcpy", "memmove",
61];
62
63fn libc_fn_param_type(func_name: &str, arg_index: usize) -> Option<UnifiedType> {
69 match (func_name, arg_index) {
70 ("memset", 0) => Some(UnifiedType::from_rust_str("*mut c_void")),
72 ("memset", 1) => Some(UnifiedType::from_rust_str("c_int")),
73 ("memset", 2) => Some(UnifiedType::from_rust_str("usize")),
74 ("memcpy", 0) | ("memmove", 0) => Some(UnifiedType::from_rust_str("*mut c_void")),
76 ("memcpy", 1) | ("memmove", 1) => Some(UnifiedType::from_rust_str("*const c_void")),
77 ("memcpy", 2) | ("memmove", 2) => Some(UnifiedType::from_rust_str("usize")),
78 ("memchr", 0) => Some(UnifiedType::from_rust_str("*const c_void")),
80 ("memchr", 1) => Some(UnifiedType::from_rust_str("c_int")),
81 ("memchr", 2) => Some(UnifiedType::from_rust_str("usize")),
82 ("memcmp", 0) | ("memcmp", 1) => Some(UnifiedType::from_rust_str("*const c_void")),
84 ("memcmp", 2) => Some(UnifiedType::from_rust_str("usize")),
85 ("strcmp", 0) | ("strcmp", 1) | ("strncmp", 0) | ("strncmp", 1) =>
87 Some(UnifiedType::from_rust_str("*const c_char")),
88 ("strncmp", 2) => Some(UnifiedType::from_rust_str("usize")),
89 ("strlen", 0) => Some(UnifiedType::from_rust_str("*const c_char")),
91 ("strcpy", 0) | ("strncpy", 0) => Some(UnifiedType::from_rust_str("*mut c_char")),
93 ("strcpy", 1) | ("strncpy", 1) => Some(UnifiedType::from_rust_str("*const c_char")),
94 ("strncpy", 2) => Some(UnifiedType::from_rust_str("usize")),
95 _ => None,
96 }
97}
98
99pub struct KnownSymbols {
105 names: HashSet<String>,
106}
107
108impl KnownSymbols {
109 pub fn new(result: &InferResult, interner: &StringInterner) -> Self {
111 let mut names = HashSet::new();
112
113 if let Some(ref dict) = result.rust_decl_dict {
115 for name in dict.fns.keys() {
116 names.insert(name.clone());
117 }
118 for name in dict.consts.keys() {
119 names.insert(name.clone());
120 }
121 for name in dict.types.keys() {
122 names.insert(name.clone());
123 }
124 for name in dict.structs.keys() {
125 names.insert(name.clone());
126 }
127 for name in &dict.enums {
128 names.insert(name.clone());
129 }
130 for name in &dict.statics {
131 names.insert(name.clone());
132 }
133 for name in &dict.static_arrays {
134 names.insert(name.clone());
135 }
136 }
137
138 for (name_id, info) in &result.infer_ctx.macros {
140 let name_str = interner.get(*name_id);
141 if info.has_body && info.is_function {
145 names.insert(name_str.to_string());
146 }
147 }
148
149 for (name_id, _) in result.inline_fn_dict.iter() {
151 let name_str = interner.get(*name_id);
152 names.insert(name_str.to_string());
153 }
154
155 let builtins = [
157 "__builtin_expect",
158 "__builtin_offsetof",
159 "offsetof",
160 "__builtin_types_compatible_p",
161 "__builtin_constant_p",
162 "__builtin_choose_expr",
163 "__builtin_unreachable",
164 "__builtin_trap",
165 "__builtin_assume",
166 "__builtin_bswap16",
167 "__builtin_bswap32",
168 "__builtin_bswap64",
169 "__builtin_popcount",
170 "__builtin_clz",
171 "__builtin_ctz",
172 "pthread_mutex_lock",
173 "pthread_mutex_unlock",
174 "pthread_rwlock_rdlock",
175 "pthread_rwlock_wrlock",
176 "pthread_rwlock_unlock",
177 "pthread_getspecific",
178 "pthread_cond_wait",
179 "pthread_cond_signal",
180 "getenv",
181 "ASSERT_IS_LITERAL",
182 "ASSERT_IS_PTR",
183 "ASSERT_NOT_PTR",
184 ];
185 for name in builtins {
186 names.insert(name.to_string());
187 }
188
189 for name in LIBC_FUNCTIONS {
191 names.insert(name.to_string());
192 }
193
194 for (name_id, _) in result.global_const_dict.iter() {
199 names.insert(interner.get(*name_id).to_string());
200 }
201
202 let rust_primitives = [
204 "true", "false", "std", "crate", "self", "super",
205 "null_mut", "null",
206 "PerlInterpreter", "my_perl",
207 "size_t", "ssize_t", "SSize_t",
210 "c_void", "c_char", "c_uchar", "c_int", "c_uint",
212 "c_long", "c_ulong", "c_short", "c_ushort",
213 ];
214 for name in rust_primitives {
215 names.insert(name.to_string());
216 }
217
218 Self { names }
219 }
220
221 fn contains(&self, name: &str) -> bool {
223 self.names.contains(name)
224 }
225
226 pub fn insert(&mut self, name: String) {
228 self.names.insert(name);
229 }
230}
231
232const RUST_KEYWORDS: &[&str] = &[
235 "as", "async", "await", "break", "const", "continue", "crate", "dyn",
237 "else", "enum", "extern", "fn", "for", "if", "impl", "in",
238 "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return",
239 "self", "Self", "static", "struct", "super", "trait", "type",
240 "unsafe", "use", "where", "while",
241 "abstract", "become", "box", "do", "final", "gen", "macro", "override",
243 "priv", "try", "typeof", "unsized", "virtual", "yield",
244];
245
246fn escape_rust_keyword(name: &str) -> String {
251 match name {
252 "__FILE__" => "file!()".to_string(),
254 "__LINE__" => "line!()".to_string(),
255 _ if RUST_KEYWORDS.contains(&name) => format!("r#{}", name),
257 _ => name.to_string(),
259 }
260}
261
262fn replace_word(s: &str, word: &str, replacement: &str) -> String {
267 if word.is_empty() {
268 return s.to_string();
269 }
270 let mut result = String::with_capacity(s.len());
271 let mut start = 0;
272 let bytes = s.as_bytes();
273 let word_bytes = word.as_bytes();
274 while let Some(pos) = s[start..].find(word) {
275 let abs_pos = start + pos;
276 let before_ok = abs_pos == 0 || !is_ident_char(bytes[abs_pos - 1]);
278 let after_pos = abs_pos + word.len();
280 let after_ok = after_pos >= bytes.len() || !is_ident_char(bytes[after_pos]);
281
282 if before_ok && after_ok {
283 result.push_str(&s[start..abs_pos]);
284 result.push_str(replacement);
285 start = after_pos;
286 } else {
287 result.push_str(&s[start..abs_pos + word_bytes.len()]);
288 start = abs_pos + word_bytes.len();
289 }
290 }
291 result.push_str(&s[start..]);
292 result
293}
294
295fn is_ident_char(b: u8) -> bool {
297 b.is_ascii_alphanumeric() || b == b'_'
298}
299
300fn bin_op_to_rust(op: BinOp) -> &'static str {
302 match op {
303 BinOp::Add => "+",
304 BinOp::Sub => "-",
305 BinOp::Mul => "*",
306 BinOp::Div => "/",
307 BinOp::Mod => "%",
308 BinOp::BitAnd => "&",
309 BinOp::BitOr => "|",
310 BinOp::BitXor => "^",
311 BinOp::Shl => "<<",
312 BinOp::Shr => ">>",
313 BinOp::Lt => "<",
314 BinOp::Gt => ">",
315 BinOp::Le => "<=",
316 BinOp::Ge => ">=",
317 BinOp::Eq => "==",
318 BinOp::Ne => "!=",
319 BinOp::LogAnd => "&&",
320 BinOp::LogOr => "||",
321 }
322}
323
324fn assign_op_to_rust(op: AssignOp) -> &'static str {
326 match op {
327 AssignOp::Assign => "=",
328 AssignOp::MulAssign => "*=",
329 AssignOp::DivAssign => "/=",
330 AssignOp::ModAssign => "%=",
331 AssignOp::AddAssign => "+=",
332 AssignOp::SubAssign => "-=",
333 AssignOp::ShlAssign => "<<=",
334 AssignOp::ShrAssign => ">>=",
335 AssignOp::AndAssign => "&=",
336 AssignOp::XorAssign => "^=",
337 AssignOp::OrAssign => "|=",
338 }
339}
340
341fn escape_char(c: u8) -> String {
343 match c {
344 b'\'' => "\\'".to_string(),
345 b'\\' => "\\\\".to_string(),
346 b'\n' => "\\n".to_string(),
347 b'\r' => "\\r".to_string(),
348 b'\t' => "\\t".to_string(),
349 c if c.is_ascii_graphic() || c == b' ' => (c as char).to_string(),
350 c => format!("\\x{:02x}", c),
351 }
352}
353
354fn escape_string(s: &[u8]) -> String {
356 s.iter().map(|&c| escape_char(c)).collect()
357}
358
359fn is_void_only_param_list(params: &[ParamDecl]) -> bool {
366 if params.len() != 1 {
367 return false;
368 }
369 let p = ¶ms[0];
370 let declarator_is_trivial = match &p.declarator {
373 None => true,
374 Some(d) => d.name.is_none() && d.derived.is_empty(),
375 };
376 let specs_is_void = p.specs.type_specs.len() == 1
377 && matches!(p.specs.type_specs[0], TypeSpec::Void);
378 declarator_is_trivial && specs_is_void
379}
380
381fn is_zero_constant(expr: &Expr) -> bool {
383 match &expr.kind {
384 ExprKind::IntLit(0) => true,
385 ExprKind::UIntLit(0) => true,
386 _ => false,
387 }
388}
389
390pub fn is_boolean_expr(expr: &Expr) -> bool {
394 match &expr.kind {
395 ExprKind::Binary { op, .. } => matches!(op,
396 BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge |
397 BinOp::Eq | BinOp::Ne | BinOp::LogAnd | BinOp::LogOr
398 ),
399 ExprKind::Cast { type_name, .. } => {
401 type_name.specs.type_specs.iter().any(|ts| {
403 matches!(ts, TypeSpec::Bool)
404 })
405 }
406 ExprKind::LogNot(_) => true,
408 _ => false,
409 }
410}
411
412
413fn is_boolean_expr_recursive(expr: &Expr, interner: &StringInterner) -> bool {
415 if is_boolean_expr(expr) {
416 return true;
417 }
418 match &expr.kind {
419 ExprKind::Call { func, args } => {
420 if let ExprKind::Ident(name) = &func.kind {
421 if interner.get(*name) == "__builtin_expect" && !args.is_empty() {
422 return is_boolean_expr_recursive(&args[0], interner);
423 }
424 }
425 }
426 ExprKind::Cast { type_name, expr: inner } => {
428 if type_name.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool)) {
429 return true;
430 }
431 return is_boolean_expr_recursive(inner, interner);
432 }
433 _ => {}
434 }
435 false
436}
437
438pub fn is_boolean_expr_with_context(
440 expr: &Expr,
441 bool_return_macros: &HashSet<InternedStr>,
442 bool_return_externals: &HashSet<InternedStr>,
443) -> bool {
444 if is_boolean_expr(expr) {
445 return true;
446 }
447 match &expr.kind {
448 ExprKind::Call { func, .. } => {
449 if let ExprKind::Ident(name) = &func.kind {
450 return bool_return_macros.contains(name)
451 || bool_return_externals.contains(name);
452 }
453 }
454 ExprKind::MacroCall { name, .. } => {
455 return bool_return_macros.contains(name)
456 || bool_return_externals.contains(name);
457 }
458 _ => {}
459 }
460 false
461}
462
463fn is_type_repr_pointer(ty: &crate::type_repr::TypeRepr) -> bool {
465 use crate::type_repr::TypeRepr;
466 match ty {
467 TypeRepr::CType { derived, .. } => {
468 derived.iter().any(|d| matches!(d, crate::type_repr::CDerivedType::Pointer { .. }))
469 }
470 TypeRepr::RustType { repr, .. } => {
471 matches!(repr, crate::type_repr::RustTypeRepr::Pointer { .. })
472 }
473 TypeRepr::Inferred(inferred) => {
474 inferred.resolved_type()
475 .map(|r| is_type_repr_pointer(r))
476 .unwrap_or(false)
477 }
478 }
479}
480
481fn best_constraint_for_macro_param(
485 info: &MacroInferInfo,
486 param: &MacroParam,
487) -> Option<crate::type_repr::TypeRepr> {
488 let mut best: Option<(&crate::type_repr::TypeRepr, u8)> = None;
489
490 if let Some(constraints) = info.type_env.get_param_constraints(param.name) {
494 for c in constraints {
495 if c.ty.is_void() { continue; }
496 let tier = c.ty.confidence_tier();
497 if best.is_none() || tier < best.unwrap().1 {
498 best = Some((&c.ty, tier));
499 }
500 }
501 }
502
503 let mut all_expr_ids: Vec<crate::ast::ExprId> = info
504 .type_env
505 .param_to_exprs
506 .get(¶m.name)
507 .map(|ids| ids.iter().cloned().collect())
508 .unwrap_or_default();
509 all_expr_ids.push(param.expr_id());
510
511 for expr_id in &all_expr_ids {
512 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
513 for c in constraints {
514 if c.ty.is_void() { continue; }
515 let tier = c.ty.confidence_tier();
516 if best.is_none() || tier < best.unwrap().1 {
517 best = Some((&c.ty, tier));
518 }
519 }
520 }
521 }
522 best.map(|(t, _)| t.clone())
523}
524
525fn substitute_idents(expr: &mut Expr, subs: &HashMap<InternedStr, &Expr>) {
532 if let ExprKind::Ident(name) = &expr.kind {
533 if let Some(replacement) = subs.get(name) {
534 *expr = (*replacement).clone();
535 return;
536 }
537 }
538 match &mut expr.kind {
539 ExprKind::Ident(_)
540 | ExprKind::IntLit(_)
541 | ExprKind::UIntLit(_)
542 | ExprKind::FloatLit(_)
543 | ExprKind::CharLit(_)
544 | ExprKind::StringLit(_)
545 | ExprKind::SizeofType(_)
546 | ExprKind::Alignof(_) => {}
547 ExprKind::Index { expr: e, index } => {
548 substitute_idents(e, subs);
549 substitute_idents(index, subs);
550 }
551 ExprKind::Call { func, args } => {
552 substitute_idents(func, subs);
553 for arg in args {
554 substitute_idents(arg, subs);
555 }
556 }
557 ExprKind::Member { expr: e, .. }
558 | ExprKind::PtrMember { expr: e, .. }
559 | ExprKind::PostInc(e)
560 | ExprKind::PostDec(e)
561 | ExprKind::PreInc(e)
562 | ExprKind::PreDec(e)
563 | ExprKind::AddrOf(e)
564 | ExprKind::Deref(e)
565 | ExprKind::UnaryPlus(e)
566 | ExprKind::UnaryMinus(e)
567 | ExprKind::BitNot(e)
568 | ExprKind::LogNot(e)
569 | ExprKind::Sizeof(e)
570 | ExprKind::Cast { expr: e, .. } => substitute_idents(e, subs),
571 ExprKind::Binary { lhs, rhs, .. }
572 | ExprKind::Assign { lhs, rhs, .. }
573 | ExprKind::Comma { lhs, rhs } => {
574 substitute_idents(lhs, subs);
575 substitute_idents(rhs, subs);
576 }
577 ExprKind::Conditional { cond, then_expr, else_expr } => {
578 substitute_idents(cond, subs);
579 substitute_idents(then_expr, subs);
580 substitute_idents(else_expr, subs);
581 }
582 ExprKind::Assert { condition, .. } => substitute_idents(condition, subs),
583 ExprKind::MacroCall { args, expanded, .. } => {
584 for arg in args {
585 substitute_idents(arg, subs);
586 }
587 substitute_idents(expanded, subs);
588 }
589 ExprKind::BuiltinCall { args, .. } => {
590 for arg in args {
591 if let crate::ast::BuiltinArg::Expr(e) = arg {
592 substitute_idents(e, subs);
593 }
594 }
595 }
596 ExprKind::CompoundLit { init, .. } => {
597 for item in init {
598 if let crate::ast::Initializer::Expr(e) = &mut item.init {
599 substitute_idents(e, subs);
600 }
601 }
602 }
603 ExprKind::StmtExpr(_) => {}
605 }
606}
607
608fn expr_yields_value_for_stmt_use(expr: &syn::Expr) -> bool {
622 match expr {
623 syn::Expr::Block(b) => {
624 matches!(b.block.stmts.last(), Some(syn::Stmt::Expr(_, None)))
625 }
626 syn::Expr::Binary(b) => matches!(
627 b.op,
628 syn::BinOp::And(_) | syn::BinOp::Or(_)
629 ),
630 syn::Expr::Unary(_) => true,
631 syn::Expr::Paren(p) => expr_yields_value_for_stmt_use(&p.expr),
633 _ => false,
634 }
635}
636
637fn is_unsigned_cast_expr(expr_str: &str) -> bool {
640 if let Some(pos) = expr_str.rfind(" as ") {
641 let after = &expr_str[pos + 4..].trim_end_matches(')');
642 matches!(*after, "usize" | "u8" | "u16" | "u32" | "u64" | "u128" | "c_uint" | "c_ulong" | "c_ulonglong")
643 } else {
644 false
645 }
646}
647
648fn is_unsigned_integer_target(ty: &str) -> bool {
651 matches!(ty,
652 "u8" | "u16" | "u32" | "u64" | "u128" | "usize" |
653 "U8" | "U16" | "U32" | "U64" |
654 "UV" | "STRLEN" | "Size_t" | "size_t" | "PERL_UINTMAX_T" |
655 "c_uchar" | "c_ushort" | "c_uint" | "c_ulong" | "c_ulonglong"
656 )
657}
658
659
660fn strip_outer_parens(s: &str) -> &str {
664 let s = s.trim();
665 if s.len() < 2 || !s.starts_with('(') || !s.ends_with(')') {
666 return s;
667 }
668 let inner = &s[1..s.len() - 1];
670 if inner.trim_start().starts_with('{') {
672 return s;
673 }
674 let mut depth = 0i32;
675 for ch in inner.chars() {
676 match ch {
677 '(' | '{' | '[' => depth += 1,
678 ')' | '}' | ']' => {
679 depth -= 1;
680 if depth < 0 {
681 return s;
683 }
684 }
685 _ => {}
686 }
687 }
688 if depth == 0 {
689 inner
690 } else {
691 s
692 }
693}
694
695fn extract_assert_message(expr: &Expr) -> Option<String> {
698 if let ExprKind::LogNot(inner) = &expr.kind {
699 if let ExprKind::StringLit(bytes) = &inner.kind {
700 return Some(String::from_utf8_lossy(bytes).into_owned());
701 }
702 }
703 None
704}
705
706fn decompose_assert_with_message(condition: &Expr) -> Option<(&Expr, String)> {
708 if let ExprKind::Binary { op: BinOp::LogOr, lhs, rhs } = &condition.kind {
709 if let Some(msg) = extract_assert_message(rhs) {
710 return Some((lhs, msg));
711 }
712 }
713 None
714}
715
716fn is_sv_subtype_cast(from: &UnifiedType, to: &UnifiedType) -> bool {
718 let inner_name = |ut: &UnifiedType| -> Option<String> {
721 match ut.inner_type()? {
722 UnifiedType::Named(name) => Some(name.clone()),
723 UnifiedType::Void => Some("c_void".to_string()),
724 _ => None,
725 }
726 };
727 let from_name = match inner_name(from) {
728 Some(n) => n,
729 None => return false,
730 };
731 let to_name = match inner_name(to) {
732 Some(n) => n,
733 None => return false,
734 };
735 const SV_SUBTYPES: &[&str] = &[
739 "GV", "HV", "AV", "CV", "IO", "p5rx", "REGEXP",
740 "gv", "hv", "av", "cv", "io", "regexp",
741 ];
742 let sv_like = |n: &str| n == "SV" || n == "sv";
743 (SV_SUBTYPES.contains(&from_name.as_str()) && sv_like(&to_name))
745 || (sv_like(&from_name) && SV_SUBTYPES.contains(&to_name.as_str()))
746 || (SV_SUBTYPES.contains(&from_name.as_str())
748 && SV_SUBTYPES.contains(&to_name.as_str()))
749 || to_name == "c_void"
751 || from_name == "c_void"
752}
753
754fn is_null_literal(expr: &Expr) -> bool {
755 match &expr.kind {
756 ExprKind::IntLit(0) => true,
757 ExprKind::Cast { expr: inner, .. } => is_null_literal(inner),
758 _ => false,
759 }
760}
761
762fn null_ptr_expr(return_type: &UnifiedType) -> String {
764 if return_type.is_const_pointer() {
765 "std::ptr::null()".to_string()
766 } else {
767 "std::ptr::null_mut()".to_string()
768 }
769}
770
771fn normalize_integer_type(ty: &str) -> Option<&'static str> {
773 match ty {
774 "u8" | "U8" | "c_uchar" => Some("u8"),
775 "u16" | "U16" | "c_ushort" => Some("u16"),
776 "u32" | "U32" | "c_uint" => Some("u32"),
777 "u64" | "U64" | "UV" | "c_ulong" | "c_ulonglong"
778 | "PERL_UINTMAX_T" => Some("u64"),
779 "i8" | "I8" | "c_schar" | "c_char" => Some("i8"),
780 "i16" | "I16" | "c_short" => Some("i16"),
781 "i32" | "I32" | "c_int" => Some("i32"),
782 "i64" | "I64" | "IV" | "c_long" | "c_longlong" => Some("i64"),
783 "usize" | "STRLEN" => Some("usize"),
784 "isize" | "SSize_t" | "ssize_t" | "PADOFFSET" => Some("isize"),
785 "Stack_off_t" => Some("i32"),
788 _ => None,
789 }
790}
791
792fn integer_types_compatible(a: &str, b: &str) -> bool {
794 if a == b { return true; }
795 matches!((a, b),
796 ("i64", "isize") | ("isize", "i64") |
797 ("u64", "usize") | ("usize", "u64")
798 )
799}
800
801fn integer_type_rank(ty: &str) -> Option<(bool, u8)> {
804 match normalize_integer_type(ty)? {
805 "u8" => Some((false, 1)), "i8" => Some((true, 1)),
806 "u16" => Some((false, 2)), "i16" => Some((true, 2)),
807 "u32" => Some((false, 4)), "i32" => Some((true, 4)),
808 "u64" => Some((false, 8)), "i64" => Some((true, 8)),
809 "usize" => Some((false, 8)), "isize" => Some((true, 8)),
810 _ => None,
811 }
812}
813
814fn wider_integer_type(a: &str, b: &str) -> Option<&'static str> {
817 let na = normalize_integer_type(a)?;
818 let nb = normalize_integer_type(b)?;
819 if na == nb { return None; }
820 let (a_signed, a_rank) = integer_type_rank(a)?;
821 let (_b_signed, b_rank) = integer_type_rank(b)?;
822 if a_rank == b_rank {
823 Some(if a_signed { nb } else { na })
825 } else if a_rank > b_rank {
826 Some(na)
827 } else {
828 Some(nb)
829 }
830}
831
832pub fn pointer_inner_compatible(a: &UnifiedType, b: &UnifiedType) -> bool {
839 let a_inner = match a { UnifiedType::Pointer { inner, .. } => inner.as_ref(), _ => return false };
840 let b_inner = match b { UnifiedType::Pointer { inner, .. } => inner.as_ref(), _ => return false };
841 type_inner_compatible(a_inner, b_inner)
842}
843
844fn type_inner_compatible(a: &UnifiedType, b: &UnifiedType) -> bool {
846 if a.is_pointer() && b.is_pointer() {
848 return pointer_inner_compatible(a, b);
849 }
850 let a_s = a.to_rust_string();
852 let b_s = b.to_rust_string();
853 if let (Some(na), Some(nb)) = (normalize_integer_type(&a_s), normalize_integer_type(&b_s)) {
854 return na == nb;
855 }
856 if a.is_void() && b.is_void() { return true; }
858 a_s == b_s
860}
861
862pub fn pointer_const_differs(a: &UnifiedType, b: &UnifiedType) -> bool {
864 if !(a.is_pointer() && b.is_pointer()) { return false; }
865 if a.is_const_pointer() == b.is_const_pointer() { return false; }
866 pointer_inner_compatible(a, b)
867}
868
869pub fn collect_must_mut_pointer_params(
874 parse_result: &ParseResult,
875 params: &[MacroParam],
876 callee_const_params: &HashMap<InternedStr, HashSet<usize>>,
877) -> HashSet<InternedStr> {
878 let param_names: HashSet<InternedStr> = params.iter().map(|p| p.name).collect();
879 let mut result = HashSet::new();
880 match parse_result {
881 ParseResult::Expression(expr) => {
882 collect_must_mut_from_expr(expr, ¶m_names, callee_const_params, &mut result);
883 }
884 ParseResult::Statement(items) => {
885 for item in items {
886 if let BlockItem::Stmt(stmt) = item {
887 collect_must_mut_from_stmt(stmt, ¶m_names, callee_const_params, &mut result);
888 }
889 }
890 }
891 ParseResult::Unparseable(_) => {}
892 }
893 result
894}
895
896pub fn collect_must_mut_from_stmt(
897 stmt: &Stmt,
898 params: &HashSet<InternedStr>,
899 callee_const: &HashMap<InternedStr, HashSet<usize>>,
900 result: &mut HashSet<InternedStr>,
901) {
902 match stmt {
903 Stmt::Expr(Some(expr), _) | Stmt::Return(Some(expr), _) => {
904 collect_must_mut_from_expr(expr, params, callee_const, result);
905 }
906 Stmt::Compound(compound) => {
907 for item in &compound.items {
908 match item {
909 BlockItem::Stmt(s) => collect_must_mut_from_stmt(s, params, callee_const, result),
910 BlockItem::Decl(decl) => {
911 for init_decl in &decl.declarators {
912 if let Some(Initializer::Expr(init)) = &init_decl.init {
913 collect_must_mut_from_expr(init, params, callee_const, result);
914 }
915 }
916 }
917 }
918 }
919 }
920 Stmt::If { cond, then_stmt, else_stmt, .. } => {
921 collect_must_mut_from_expr(cond, params, callee_const, result);
922 collect_must_mut_from_stmt(then_stmt, params, callee_const, result);
923 if let Some(e) = else_stmt {
924 collect_must_mut_from_stmt(e, params, callee_const, result);
925 }
926 }
927 Stmt::While { cond, body, .. } | Stmt::DoWhile { cond, body, .. } => {
928 collect_must_mut_from_expr(cond, params, callee_const, result);
929 collect_must_mut_from_stmt(body, params, callee_const, result);
930 }
931 Stmt::For { init, cond, step, body, .. } => {
932 if let Some(ForInit::Expr(e)) = init { collect_must_mut_from_expr(e, params, callee_const, result); }
933 if let Some(e) = cond { collect_must_mut_from_expr(e, params, callee_const, result); }
934 if let Some(e) = step { collect_must_mut_from_expr(e, params, callee_const, result); }
935 collect_must_mut_from_stmt(body, params, callee_const, result);
936 }
937 Stmt::Switch { expr, body, .. } => {
938 collect_must_mut_from_expr(expr, params, callee_const, result);
939 collect_must_mut_from_stmt(body, params, callee_const, result);
940 }
941 _ => {}
942 }
943}
944
945pub fn collect_must_mut_from_expr(
946 expr: &Expr,
947 params: &HashSet<InternedStr>,
948 callee_const: &HashMap<InternedStr, HashSet<usize>>,
949 result: &mut HashSet<InternedStr>,
950) {
951 match &expr.kind {
952 ExprKind::Assign { lhs, rhs, .. } => {
954 mark_lvalue_mut(lhs, params, result);
955 collect_must_mut_from_expr(lhs, params, callee_const, result);
956 collect_must_mut_from_expr(rhs, params, callee_const, result);
957 }
958 ExprKind::PreInc(inner) | ExprKind::PreDec(inner) |
960 ExprKind::PostInc(inner) | ExprKind::PostDec(inner) => {
961 mark_lvalue_mut(inner, params, result);
962 collect_must_mut_from_expr(inner, params, callee_const, result);
963 }
964 ExprKind::Call { func, args } => {
966 if let ExprKind::Ident(func_name) = &func.kind {
968 let const_arg_positions = callee_const.get(func_name);
969 for (i, arg) in args.iter().enumerate() {
970 if let ExprKind::Ident(arg_name) = &arg.kind {
971 if params.contains(arg_name) {
972 let is_const_at_callee = const_arg_positions
974 .map_or(false, |positions| positions.contains(&i));
975 if !is_const_at_callee {
976 result.insert(*arg_name);
978 }
979 }
980 }
981 collect_must_mut_from_expr(arg, params, callee_const, result);
982 }
983 } else {
984 for arg in args {
985 collect_must_mut_from_expr(arg, params, callee_const, result);
986 }
987 }
988 collect_must_mut_from_expr(func, params, callee_const, result);
989 }
990 ExprKind::Binary { lhs, rhs, .. } | ExprKind::Comma { lhs, rhs } => {
992 collect_must_mut_from_expr(lhs, params, callee_const, result);
993 collect_must_mut_from_expr(rhs, params, callee_const, result);
994 }
995 ExprKind::Conditional { cond, then_expr, else_expr } => {
996 collect_must_mut_from_expr(cond, params, callee_const, result);
997 collect_must_mut_from_expr(then_expr, params, callee_const, result);
998 collect_must_mut_from_expr(else_expr, params, callee_const, result);
999 }
1000 ExprKind::MacroCall { name, args, expanded, .. } => {
1002 let const_arg_positions = callee_const.get(name);
1003 for (i, arg) in args.iter().enumerate() {
1004 if let ExprKind::Ident(arg_name) = &arg.kind {
1005 if params.contains(arg_name) {
1006 let is_const_at_callee = const_arg_positions
1007 .map_or(false, |positions| positions.contains(&i));
1008 if !is_const_at_callee {
1009 result.insert(*arg_name);
1010 }
1011 }
1012 }
1013 collect_must_mut_from_expr(arg, params, callee_const, result);
1014 }
1015 collect_must_mut_from_expr(expanded, params, callee_const, result);
1016 }
1017 ExprKind::Deref(inner) | ExprKind::UnaryMinus(inner) | ExprKind::BitNot(inner) |
1018 ExprKind::LogNot(inner) | ExprKind::AddrOf(inner) |
1019 ExprKind::Cast { expr: inner, .. } => {
1020 collect_must_mut_from_expr(inner, params, callee_const, result);
1021 }
1022 ExprKind::Member { expr: inner, .. } | ExprKind::PtrMember { expr: inner, .. } => {
1023 collect_must_mut_from_expr(inner, params, callee_const, result);
1024 }
1025 ExprKind::Sizeof(inner) => {
1026 collect_must_mut_from_expr(inner, params, callee_const, result);
1027 }
1028 ExprKind::Assert { condition, .. } => {
1029 collect_must_mut_from_expr(condition, params, callee_const, result);
1030 }
1031 ExprKind::StmtExpr(compound) => {
1032 for item in &compound.items {
1033 match item {
1034 BlockItem::Stmt(s) => collect_must_mut_from_stmt(s, params, callee_const, result),
1035 BlockItem::Decl(decl) => {
1036 for init_decl in &decl.declarators {
1037 if let Some(Initializer::Expr(init)) = &init_decl.init {
1038 collect_must_mut_from_expr(init, params, callee_const, result);
1039 }
1040 }
1041 }
1042 }
1043 }
1044 }
1045 _ => {}
1046 }
1047}
1048
1049pub fn mark_lvalue_mut(expr: &Expr, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1051 match &expr.kind {
1052 ExprKind::Deref(inner) => {
1054 if let ExprKind::Ident(name) = &inner.kind {
1055 if params.contains(name) {
1056 result.insert(*name);
1057 }
1058 }
1059 mark_lvalue_mut(inner, params, result);
1061 }
1062 ExprKind::PtrMember { expr: inner, .. } => {
1064 if let ExprKind::Ident(name) = &inner.kind {
1065 if params.contains(name) {
1066 result.insert(*name);
1067 }
1068 }
1069 mark_lvalue_mut(inner, params, result);
1070 }
1071 ExprKind::Member { expr: inner, .. } => {
1073 mark_lvalue_mut(inner, params, result);
1074 }
1075 ExprKind::Cast { expr: inner, type_name } => {
1077 if let ExprKind::Ident(name) = &inner.kind {
1078 if params.contains(name) {
1079 let has_non_const_ptr = type_name.declarator.as_ref()
1081 .map(|d| d.derived.iter().any(|dd| {
1082 matches!(dd, crate::ast::DerivedDecl::Pointer(q) if !q.is_const)
1083 }))
1084 .unwrap_or(false);
1085 if has_non_const_ptr {
1086 result.insert(*name);
1087 }
1088 }
1089 }
1090 mark_lvalue_mut(inner, params, result);
1091 }
1092 ExprKind::MacroCall { expanded, args, .. } => {
1094 mark_lvalue_mut(expanded, params, result);
1095 for arg in args {
1097 mark_lvalue_mut(arg, params, result);
1098 }
1099 }
1100 ExprKind::Call { args, .. } => {
1103 for arg in args {
1104 if let ExprKind::Ident(name) = &arg.kind {
1105 if params.contains(name) {
1106 result.insert(*name);
1107 }
1108 }
1109 mark_lvalue_mut(arg, params, result);
1110 }
1111 }
1112 _ => {}
1113 }
1114}
1115
1116fn collect_mut_params(parse_result: &ParseResult, params: &[MacroParam]) -> HashSet<InternedStr> {
1117 let param_names: HashSet<InternedStr> = params.iter().map(|p| p.name).collect();
1118 let mut result = HashSet::new();
1119 match parse_result {
1120 ParseResult::Expression(expr) => collect_mut_params_from_expr(expr, ¶m_names, &mut result),
1121 ParseResult::Statement(items) => {
1122 for item in items {
1123 if let BlockItem::Stmt(stmt) = item {
1124 collect_mut_params_from_stmt(stmt, ¶m_names, &mut result);
1125 }
1126 }
1127 }
1128 ParseResult::Unparseable(_) => {}
1129 }
1130 result
1131}
1132
1133fn collect_mut_params_from_expr(expr: &Expr, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1134 match &expr.kind {
1135 ExprKind::AddrOf(inner) => {
1136 if let ExprKind::Ident(name) = &inner.kind {
1138 if params.contains(name) {
1139 result.insert(*name);
1140 }
1141 }
1142 collect_mut_params_from_expr(inner, params, result);
1143 }
1144 ExprKind::Assign { lhs, rhs, .. } => {
1145 if let ExprKind::Ident(name) = &lhs.kind {
1147 if params.contains(name) {
1148 result.insert(*name);
1149 }
1150 }
1151 collect_mut_params_from_expr(lhs, params, result);
1152 collect_mut_params_from_expr(rhs, params, result);
1153 }
1154 ExprKind::PreInc(inner) | ExprKind::PreDec(inner) |
1155 ExprKind::PostInc(inner) | ExprKind::PostDec(inner) => {
1156 if let ExprKind::Ident(name) = &inner.kind {
1157 if params.contains(name) {
1158 result.insert(*name);
1159 }
1160 }
1161 collect_mut_params_from_expr(inner, params, result);
1162 }
1163 ExprKind::Binary { lhs, rhs, .. } => {
1165 collect_mut_params_from_expr(lhs, params, result);
1166 collect_mut_params_from_expr(rhs, params, result);
1167 }
1168 ExprKind::Deref(inner) | ExprKind::UnaryMinus(inner) | ExprKind::BitNot(inner) |
1169 ExprKind::LogNot(inner) | ExprKind::Cast { expr: inner, .. } => {
1170 collect_mut_params_from_expr(inner, params, result);
1171 }
1172 ExprKind::Call { func, args } => {
1173 collect_mut_params_from_expr(func, params, result);
1174 for arg in args {
1175 collect_mut_params_from_expr(arg, params, result);
1176 }
1177 }
1178 ExprKind::MacroCall { expanded, args, .. } => {
1179 collect_mut_params_from_expr(expanded, params, result);
1180 for arg in args {
1181 collect_mut_params_from_expr(arg, params, result);
1182 }
1183 }
1184 ExprKind::Conditional { cond, then_expr, else_expr } => {
1185 collect_mut_params_from_expr(cond, params, result);
1186 collect_mut_params_from_expr(then_expr, params, result);
1187 collect_mut_params_from_expr(else_expr, params, result);
1188 }
1189 ExprKind::Comma { lhs, rhs } => {
1190 collect_mut_params_from_expr(lhs, params, result);
1191 collect_mut_params_from_expr(rhs, params, result);
1192 }
1193 ExprKind::Member { expr: inner, .. } | ExprKind::PtrMember { expr: inner, .. } => {
1194 collect_mut_params_from_expr(inner, params, result);
1195 }
1196 ExprKind::StmtExpr(compound) => {
1197 for item in &compound.items {
1198 if let BlockItem::Stmt(stmt) = item {
1199 collect_mut_params_from_stmt(stmt, params, result);
1200 }
1201 }
1202 }
1203 _ => {}
1204 }
1205}
1206
1207fn collect_mut_params_from_stmt(stmt: &Stmt, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1208 match stmt {
1209 Stmt::Expr(Some(expr), _) => collect_mut_params_from_expr(expr, params, result),
1210 Stmt::Return(Some(expr), _) => collect_mut_params_from_expr(expr, params, result),
1211 Stmt::If { cond, then_stmt, else_stmt, .. } => {
1212 collect_mut_params_from_expr(cond, params, result);
1213 collect_mut_params_from_stmt(then_stmt, params, result);
1214 if let Some(else_s) = else_stmt {
1215 collect_mut_params_from_stmt(else_s, params, result);
1216 }
1217 }
1218 Stmt::Compound(compound) => {
1219 for item in &compound.items {
1220 if let BlockItem::Stmt(s) = item {
1221 collect_mut_params_from_stmt(s, params, result);
1222 }
1223 }
1224 }
1225 Stmt::While { cond, body, .. } | Stmt::DoWhile { body, cond, .. } => {
1226 collect_mut_params_from_expr(cond, params, result);
1227 collect_mut_params_from_stmt(body, params, result);
1228 }
1229 Stmt::For { init, cond, step, body, .. } => {
1230 if let Some(ForInit::Expr(e)) = init {
1231 collect_mut_params_from_expr(e, params, result);
1232 }
1233 if let Some(c) = cond {
1234 collect_mut_params_from_expr(c, params, result);
1235 }
1236 if let Some(s) = step {
1237 collect_mut_params_from_expr(s, params, result);
1238 }
1239 collect_mut_params_from_stmt(body, params, result);
1240 }
1241 _ => {}
1242 }
1243}
1244
1245fn type_str_is_fn_pointer(ty_str: &str) -> bool {
1252 ty_str.contains("fn(") || ty_str.contains("fn (")
1253}
1254
1255fn build_field_type_map(dict: Option<&RustDeclDict>) -> HashMap<String, UnifiedType> {
1256 let mut map: HashMap<String, UnifiedType> = HashMap::new();
1257 let mut conflicts: HashSet<String> = HashSet::new();
1258 if let Some(dict) = dict {
1259 for st in dict.structs.values() {
1260 for field in &st.fields {
1261 if conflicts.contains(&field.name) {
1262 continue;
1263 }
1264 match map.entry(field.name.clone()) {
1265 std::collections::hash_map::Entry::Vacant(e) => {
1266 e.insert(field.uty.clone());
1267 }
1268 std::collections::hash_map::Entry::Occupied(e) => {
1269 if e.get() != &field.uty {
1270 conflicts.insert(field.name.clone());
1271 e.remove();
1272 }
1273 }
1274 }
1275 }
1276 }
1277 for ((_struct, method), ret_ty) in &dict.bitfield_method_types {
1282 if conflicts.contains(method) {
1283 continue;
1284 }
1285 let uty = UnifiedType::from_rust_str(ret_ty);
1286 match map.entry(method.clone()) {
1287 std::collections::hash_map::Entry::Vacant(e) => {
1288 e.insert(uty);
1289 }
1290 std::collections::hash_map::Entry::Occupied(e) => {
1291 if e.get() != &uty {
1292 conflicts.insert(method.clone());
1293 e.remove();
1294 }
1295 }
1296 }
1297 }
1298 }
1299 map
1300}
1301
1302#[derive(Debug, Clone)]
1304pub struct CodegenConfig {
1305 pub emit_inline_fns: bool,
1307 pub emit_macros: bool,
1309 pub include_source_location: bool,
1311 pub use_statements: Vec<String>,
1314 pub dump_ast_for: Option<String>,
1316 pub dump_types_for: Option<String>,
1318}
1319
1320impl Default for CodegenConfig {
1321 fn default() -> Self {
1322 Self {
1323 emit_inline_fns: true,
1324 emit_macros: true,
1325 include_source_location: true,
1326 use_statements: Vec::new(),
1327 dump_ast_for: None,
1328 dump_types_for: None,
1329 }
1330 }
1331}
1332
1333impl CodegenConfig {
1334 pub fn default_use_statements() -> Vec<String> {
1339 vec![
1340 "#[allow(unused_imports)] use std::ffi::{c_void, c_char, c_uchar, c_int, c_uint, c_long, c_ulong, c_short, c_ushort}".to_string(),
1343 "#[allow(non_camel_case_types, dead_code)] type size_t = usize".to_string(),
1344 "#[allow(non_camel_case_types, dead_code)] type ssize_t = isize".to_string(),
1345 "#[allow(non_camel_case_types, dead_code)] type SSize_t = isize".to_string(),
1346 ]
1347 }
1348
1349 pub fn with_use_statements(mut self, statements: Vec<String>) -> Self {
1351 self.use_statements = statements;
1352 self
1353 }
1354
1355 pub fn add_use_statement(mut self, statement: impl Into<String>) -> Self {
1357 self.use_statements.push(statement.into());
1358 self
1359 }
1360}
1361
1362#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1364pub enum GenerateStatus {
1365 Success,
1367 ParseFailed,
1369 TypeIncomplete,
1371 CallsUnavailable,
1373 ContainsGoto,
1375 GenericUnsupported,
1377 Skip,
1379}
1380
1381fn stmt_contains_goto(stmt: &Stmt) -> bool {
1383 match stmt {
1384 Stmt::Goto(_, _) => true,
1385 Stmt::Compound(cs) => block_items_contain_goto(&cs.items),
1386 Stmt::If { then_stmt, else_stmt, .. } => {
1387 stmt_contains_goto(then_stmt)
1388 || else_stmt.as_ref().is_some_and(|s| stmt_contains_goto(s))
1389 }
1390 Stmt::Switch { body, .. }
1391 | Stmt::While { body, .. }
1392 | Stmt::For { body, .. } => stmt_contains_goto(body),
1393 Stmt::DoWhile { body, .. } => stmt_contains_goto(body),
1394 Stmt::Label { stmt, .. } => stmt_contains_goto(stmt),
1395 Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => stmt_contains_goto(stmt),
1396 _ => false,
1397 }
1398}
1399
1400fn block_items_contain_goto(items: &[BlockItem]) -> bool {
1402 items.iter().any(|item| match item {
1403 BlockItem::Stmt(stmt) => stmt_contains_goto(stmt),
1404 BlockItem::Decl(_) => false,
1405 })
1406}
1407
1408fn stmt_contains_top_level_break(stmt: &Stmt) -> bool {
1411 match stmt {
1412 Stmt::Break(_) => true,
1413 Stmt::Compound(cs) => cs.items.iter().any(|item| match item {
1414 BlockItem::Stmt(s) => stmt_contains_top_level_break(s),
1415 BlockItem::Decl(_) => false,
1416 }),
1417 Stmt::If { then_stmt, else_stmt, .. } => {
1418 stmt_contains_top_level_break(then_stmt)
1419 || else_stmt.as_ref().is_some_and(|s| stmt_contains_top_level_break(s))
1420 }
1421 Stmt::Label { stmt, .. } => stmt_contains_top_level_break(stmt),
1422 _ => false,
1425 }
1426}
1427
1428#[derive(Debug, Clone, Default)]
1430pub struct CodegenStats {
1431 pub macros_success: usize,
1433 pub macros_parse_failed: usize,
1435 pub macros_type_incomplete: usize,
1437 pub macros_calls_unavailable: usize,
1439 pub macros_cascade_unavailable: usize,
1441 pub macros_generic_unsupported: usize,
1443 pub macros_unresolved_names: usize,
1445 pub inline_fns_success: usize,
1447 pub inline_fns_type_incomplete: usize,
1449 pub inline_fns_unresolved_names: usize,
1451 pub inline_fns_cascade_unavailable: usize,
1453 pub inline_fns_contains_goto: usize,
1455}
1456
1457#[derive(Debug, Clone)]
1459pub struct GeneratedCode {
1460 pub code: String,
1462 pub incomplete_count: usize,
1464 pub unresolved_names: Vec<String>,
1466 pub used_libc_fns: HashSet<String>,
1468 pub codegen_errors: Vec<String>,
1470}
1471
1472impl GeneratedCode {
1473 pub fn is_complete(&self) -> bool {
1475 self.incomplete_count == 0
1476 }
1477
1478 pub fn has_unresolved_names(&self) -> bool {
1480 !self.unresolved_names.is_empty()
1481 }
1482}
1483
1484pub struct RustCodegen<'a> {
1490 interner: &'a StringInterner,
1491 enum_dict: &'a EnumDict,
1493 macro_ctx: &'a MacroInferContext,
1495 bindings_info: BindingsInfo,
1497 buffer: String,
1499 incomplete_count: usize,
1501 current_type_param_map: HashMap<InternedStr, String>,
1504 current_literal_string_params: HashSet<InternedStr>,
1506 current_return_type: Option<UnifiedType>,
1508 param_substitutions: HashMap<InternedStr, String>,
1511 current_param_types: HashMap<InternedStr, UnifiedType>,
1514 known_symbols: &'a KnownSymbols,
1516 current_local_names: HashSet<InternedStr>,
1518 unresolved_names: Vec<String>,
1520 used_libc_fns: HashSet<String>,
1522 rust_decl_dict: Option<&'a RustDeclDict>,
1524 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1526 fields_dict: Option<&'a crate::fields_dict::FieldsDict>,
1528 field_type_map: HashMap<String, UnifiedType>,
1530 dump_ast_for: Option<String>,
1532 dump_types_for: Option<String>,
1534 const_pointer_positions: HashSet<usize>,
1536 mut_local_names: HashSet<InternedStr>,
1538 codegen_errors: Vec<String>,
1540 is_bool_return: bool,
1542 bool_return_macros: HashSet<InternedStr>,
1544 perl_threaded: bool,
1546}
1547
1548pub struct CodegenDriver<'a, W: Write> {
1553 writer: W,
1554 interner: &'a StringInterner,
1555 enum_dict: &'a EnumDict,
1557 macro_ctx: &'a MacroInferContext,
1559 bindings_info: BindingsInfo,
1561 config: CodegenConfig,
1562 stats: CodegenStats,
1563 used_libc_fns: HashSet<String>,
1565 successfully_generated_inlines: HashSet<InternedStr>,
1567 generatable_macros: HashSet<InternedStr>,
1569 const_pointer_params: HashMap<InternedStr, HashSet<usize>>,
1571 bool_return_macros: HashSet<InternedStr>,
1573 perl_threaded: bool,
1575}
1576
1577impl<'a> RustCodegen<'a> {
1578 pub fn new(
1580 interner: &'a StringInterner,
1581 enum_dict: &'a EnumDict,
1582 macro_ctx: &'a MacroInferContext,
1583 bindings_info: BindingsInfo,
1584 known_symbols: &'a KnownSymbols,
1585 rust_decl_dict: Option<&'a RustDeclDict>,
1586 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1587 ) -> Self {
1588 Self {
1589 interner,
1590 enum_dict,
1591 macro_ctx,
1592 bindings_info,
1593 buffer: String::new(),
1594 incomplete_count: 0,
1595 current_type_param_map: HashMap::new(),
1596 current_literal_string_params: HashSet::new(),
1597 current_return_type: None,
1598 param_substitutions: HashMap::new(),
1599 current_param_types: HashMap::new(),
1600 known_symbols,
1601 current_local_names: HashSet::new(),
1602 unresolved_names: Vec::new(),
1603 used_libc_fns: HashSet::new(),
1604 rust_decl_dict,
1605 inline_fn_dict,
1606 fields_dict: None,
1607 field_type_map: build_field_type_map(rust_decl_dict),
1608 dump_ast_for: None,
1609 dump_types_for: None,
1610 const_pointer_positions: HashSet::new(),
1611 is_bool_return: false,
1612 bool_return_macros: HashSet::new(),
1613 mut_local_names: HashSet::new(),
1614 codegen_errors: Vec::new(),
1615 perl_threaded: true,
1618 }
1619 }
1620
1621 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
1623 self.perl_threaded = threaded;
1624 self
1625 }
1626
1627 pub fn with_dump_ast_for(mut self, name: Option<String>) -> Self {
1629 self.dump_ast_for = name;
1630 self
1631 }
1632
1633 pub fn with_dump_types_for(mut self, name: Option<String>) -> Self {
1634 self.dump_types_for = name;
1635 self
1636 }
1637
1638 pub fn with_fields_dict(mut self, dict: &'a crate::fields_dict::FieldsDict) -> Self {
1640 self.fields_dict = Some(dict);
1641 for (_name, def) in dict.iter_struct_defs() {
1646 for m in &def.members {
1647 let member_name = self.interner.get(m.name).to_string();
1648 if self.field_type_map.contains_key(&member_name) {
1649 continue;
1650 }
1651 let rust_ty = m.type_repr.to_rust_string(self.interner);
1652 self.field_type_map
1653 .insert(member_name, UnifiedType::from_rust_str(&rust_ty));
1654 }
1655 }
1656 self
1657 }
1658
1659 pub fn with_const_pointer_positions(mut self, positions: HashSet<usize>) -> Self {
1661 self.const_pointer_positions = positions;
1662 self
1663 }
1664
1665 pub fn with_bool_return(mut self, is_bool: bool, bool_macros: HashSet<InternedStr>) -> Self {
1667 self.is_bool_return = is_bool;
1668 self.bool_return_macros = bool_macros;
1669 self
1670 }
1671
1672 fn dump_type_info(&self, name_str: &str, info: &MacroInferInfo, params_str: &str, return_type: &str) {
1675 eprintln!("=== Type dump for {} ===", name_str);
1676 for (i, p) in info.params.iter().enumerate() {
1678 let pname = self.interner.get(p.name);
1679 let is_const = info.const_pointer_positions.contains(&i);
1680 let expr_ids: Vec<_> = info.type_env.param_to_exprs
1682 .get(&p.name)
1683 .map(|ids| ids.iter().cloned().collect())
1684 .unwrap_or_default();
1685 let mut all_ids = expr_ids;
1686 all_ids.push(p.expr_id());
1687 eprintln!(" param[{}] {} (const_position={})", i, pname, is_const);
1688 for eid in &all_ids {
1689 if let Some(constraints) = info.type_env.expr_constraints.get(eid) {
1690 for c in constraints {
1691 eprintln!(" constraint: tier={} rust={} context={} source={:?}",
1692 c.ty.confidence_tier(),
1693 c.ty.to_rust_string(self.interner),
1694 c.context,
1695 match &c.ty {
1696 crate::type_repr::TypeRepr::CType { source, .. } => format!("{:?}", source),
1697 crate::type_repr::TypeRepr::RustType { source, .. } => format!("{:?}", source),
1698 crate::type_repr::TypeRepr::Inferred(i) => format!("Inferred({:?})", std::mem::discriminant(i)),
1699 }
1700 );
1701 }
1702 }
1703 }
1704 }
1705 eprintln!(" params_str: {}", params_str);
1706 eprintln!(" return_type: {}", return_type);
1708 eprintln!(" is_bool_return: {}", info.is_bool_return);
1709 if let Some(ty) = info.get_return_type() {
1710 eprintln!(" return TypeRepr: tier={} rust={}", ty.confidence_tier(), ty.to_rust_string(self.interner));
1711 }
1712 if !info.type_env.return_constraints.is_empty() {
1714 eprintln!(" return_constraints:");
1715 for c in &info.type_env.return_constraints {
1716 eprintln!(" tier={} rust={} context={}", c.ty.confidence_tier(), c.ty.to_rust_string(self.interner), c.context);
1717 }
1718 }
1719 if let ParseResult::Expression(ref expr) = info.parse_result {
1721 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
1722 eprintln!(" root expr constraints:");
1723 for c in constraints {
1724 eprintln!(" tier={} rust={} context={}",
1725 c.ty.confidence_tier(),
1726 c.ty.to_rust_string(self.interner),
1727 c.context,
1728 );
1729 }
1730 }
1731 }
1732 eprintln!("=== End type dump ===");
1733 }
1734
1735 fn dump_ast_comment_for_expr(&mut self, name_str: &str, parse_result: &ParseResult) {
1736 if self.dump_ast_for.as_deref() != Some(name_str) {
1737 return;
1738 }
1739 let sexp = match parse_result {
1740 ParseResult::Expression(expr) => {
1741 let mut buf = Vec::new();
1742 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1743 let _ = printer.print_expr(expr);
1744 String::from_utf8_lossy(&buf).into_owned()
1745 }
1746 ParseResult::Statement(block_items) => {
1747 let mut buf = Vec::new();
1748 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1749 for item in block_items {
1750 if let BlockItem::Stmt(stmt) = item {
1751 let _ = printer.print_stmt(stmt);
1752 } else if let BlockItem::Decl(decl) = item {
1753 let _ = printer.print_declaration(decl);
1754 }
1755 }
1756 String::from_utf8_lossy(&buf).into_owned()
1757 }
1758 ParseResult::Unparseable(msg) => {
1759 format!("(unparseable: {})", msg.as_deref().unwrap_or("unknown"))
1760 }
1761 };
1762 self.writeln(&format!("// [AST dump for {}]", name_str));
1763 for line in sexp.lines() {
1764 self.writeln(&format!("// {}", line));
1765 }
1766 }
1767
1768 fn dump_ast_comment_for_body(&mut self, name_str: &str, body: &CompoundStmt) {
1770 if self.dump_ast_for.as_deref() != Some(name_str) {
1771 return;
1772 }
1773 let mut buf = Vec::new();
1774 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1775 for item in &body.items {
1776 match item {
1777 BlockItem::Stmt(stmt) => { let _ = printer.print_stmt(stmt); }
1778 BlockItem::Decl(decl) => { let _ = printer.print_declaration(decl); }
1779 }
1780 }
1781 let sexp = String::from_utf8_lossy(&buf).into_owned();
1782 self.writeln(&format!("// [AST dump for {}]", name_str));
1783 for line in sexp.lines() {
1784 self.writeln(&format!("// {}", line));
1785 }
1786 }
1787
1788 fn try_expand_call_as_lvalue_syn(&mut self, func: &Expr, args: &[Expr],
1792 info: Option<&MacroInferInfo>) -> Option<syn::Expr> {
1793 if let ExprKind::Ident(name) = &func.kind {
1794 if self.should_emit_as_macro_call(*name) {
1795 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
1796 if let ParseResult::Expression(body) = ¯o_info.parse_result {
1797 let body = body.clone();
1798 let saved_params = std::mem::take(&mut self.param_substitutions);
1799 for (i, param) in macro_info.params.iter().enumerate() {
1800 if let Some(arg) = args.get(i) {
1801 let arg_syn = self.build_syn_expr(arg, info);
1802 let arg_str = crate::syn_codegen::expr_to_string(&arg_syn);
1803 self.param_substitutions.insert(param.name, arg_str);
1804 }
1805 }
1806 let body_syn = self.build_syn_expr(&body, info);
1807 self.param_substitutions = saved_params;
1808 return Some(body_syn);
1809 }
1810 }
1811 }
1812 }
1813 None
1814 }
1815
1816
1817 fn wrap_as_bool_condition_inline(&self, expr: &Expr, expr_str: &str) -> String {
1819 self.wrap_as_bool_condition(expr, expr_str, None)
1820 }
1821
1822 fn infer_expr_type_inline(&self, expr: &Expr) -> Option<UnifiedType> {
1824 self.infer_expr_type_unified(expr, None)
1825 }
1826
1827 fn type_name_to_type_str_readonly(&self, type_name: &crate::ast::TypeName) -> String {
1829 let pointer_count = type_name.declarator.as_ref()
1831 .map(|d| d.derived.iter().filter(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer(_))).count())
1832 .unwrap_or(0);
1833 let is_const_ptr = pointer_count == 1 && type_name.specs.qualifiers.is_const;
1839 let base = self.base_type_str_readonly(&type_name.specs.type_specs);
1841 let mut result = base;
1843 for _ in 0..pointer_count {
1844 let prefix = if is_const_ptr { "*const " } else { "*mut " };
1845 result = format!("{}{}", prefix, result);
1846 }
1847 result
1848 }
1849
1850 fn base_type_str_readonly(&self, type_specs: &[TypeSpec]) -> String {
1852 for spec in type_specs {
1854 if let TypeSpec::TypedefName(name) = spec {
1855 return self.interner.get(*name).to_string();
1856 }
1857 }
1858 for spec in type_specs {
1860 match spec {
1861 TypeSpec::Struct(s) | TypeSpec::Union(s) => {
1862 if let Some(n) = &s.name {
1863 return self.interner.get(*n).to_string();
1864 }
1865 }
1866 TypeSpec::Enum(e) => {
1867 if let Some(n) = &e.name {
1868 return self.interner.get(*n).to_string();
1869 }
1870 }
1871 _ => {}
1872 }
1873 }
1874 let mut is_void = false;
1875 let mut is_char = false;
1876 let mut is_int = false;
1877 let mut is_short = false;
1878 let mut is_long = 0usize;
1879 let mut is_unsigned = false;
1880 for spec in type_specs {
1881 match spec {
1882 TypeSpec::Void => is_void = true,
1883 TypeSpec::Char => is_char = true,
1884 TypeSpec::Int => is_int = true,
1885 TypeSpec::Short => is_short = true,
1886 TypeSpec::Long => is_long += 1,
1887 TypeSpec::Unsigned => is_unsigned = true,
1888 TypeSpec::Signed => {}
1889 TypeSpec::Bool => return "bool".to_string(),
1890 _ => {}
1891 }
1892 }
1893 if is_void { return "c_void".to_string(); }
1894 if is_char { return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() }; }
1895 if is_short { return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() }; }
1896 if is_long >= 2 { return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() }; }
1897 if is_long == 1 { return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() }; }
1898 if is_int || is_unsigned { return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() }; }
1899 "c_int".to_string()
1900 }
1901
1902 fn infer_expr_type(&self, expr: &Expr, info: &MacroInferInfo) -> Option<UnifiedType> {
1904 self.infer_expr_type_unified(expr, Some(info))
1905 }
1906
1907 fn infer_expr_type_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> Option<UnifiedType> {
1916 match &expr.kind {
1917 ExprKind::Ident(name) => {
1918 if let Some(ut) = self.current_param_types.get(name) {
1920 return Some(ut.clone());
1921 }
1922 if let Some(info) = info {
1924 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
1926 let mut best: Option<(UnifiedType, u8)> = None;
1927 for expr_id in expr_ids {
1928 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
1929 for c in constraints {
1930 if c.ty.is_void() { continue; }
1931 let tier = c.ty.confidence_tier();
1932 if best.is_none() || tier < best.as_ref().unwrap().1 {
1933 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
1934 }
1935 }
1936 }
1937 }
1938 if let Some((ut, _)) = best {
1939 return Some(ut);
1940 }
1941 }
1942 if let Some(constraints) = info.type_env.param_constraints.get(name) {
1944 let mut best: Option<(UnifiedType, u8)> = None;
1945 for c in constraints {
1946 if c.ty.is_void() { continue; }
1947 let tier = c.ty.confidence_tier();
1948 if best.is_none() || tier < best.as_ref().unwrap().1 {
1949 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
1950 }
1951 }
1952 if let Some((ut, _)) = best {
1953 return Some(ut);
1954 }
1955 }
1956 }
1957 if let Some(dict) = self.rust_decl_dict {
1959 let name_str = self.interner.get(*name);
1960 if let Some(c) = dict.consts.get(name_str) {
1961 return Some(c.uty.clone());
1962 }
1963 if let Some(ty_str) = dict.static_types.get(name_str) {
1965 return Some(UnifiedType::from_rust_str(ty_str));
1966 }
1967 }
1968 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
1972 let enum_str = self.interner.get(enum_name).to_string();
1973 return Some(UnifiedType::Named(enum_str));
1974 }
1975 None
1976 }
1977 ExprKind::Cast { type_name, .. } => {
1978 Some(UnifiedType::from_rust_str(&self.type_name_to_type_str_readonly(type_name)))
1979 }
1980 ExprKind::Member { expr: base, member } | ExprKind::PtrMember { expr: base, member } => {
1981 let resolve_struct_name = |this: &Self| -> Option<String> {
1986 if let Some(info_ref) = info {
1988 if let Some(constraints) = info_ref.type_env.expr_constraints.get(&base.id) {
1989 if let Some(base_ty) = constraints.first().map(|c| &c.ty) {
1990 let sn = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
1991 base_ty.pointee_name()
1992 } else {
1993 base_ty.type_name()
1994 };
1995 if let Some(n) = sn {
1996 return Some(this.interner.get(n).to_string());
1997 }
1998 }
1999 }
2000 }
2001 let base_ut = this.infer_expr_type_unified(base, info)?;
2004 let target = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
2005 base_ut.inner_type()?
2006 } else {
2007 &base_ut
2008 };
2009 if let UnifiedType::Named(n) = target {
2010 return Some(n.clone());
2011 }
2012 None
2013 };
2014
2015 let member_str = self.interner.get(*member);
2016 let fd_ty: Option<UnifiedType> = self.fields_dict.and_then(|fd| {
2023 let struct_name_str = resolve_struct_name(self)?;
2024 let struct_name = self.interner.lookup(&struct_name_str)?;
2025 let member_ty = fd.member_type(struct_name, *member)?;
2026 let rust_ty = member_ty.to_rust_string(self.interner);
2027 if rust_ty.contains("/* fn */") {
2028 return None;
2029 }
2030 Some(UnifiedType::from_rust_str(&rust_ty))
2031 });
2032 let ftm_ty = self.field_type_map.get(member_str).cloned();
2033 match (&fd_ty, &ftm_ty) {
2036 (Some(fd_ut), Some(ftm_ut))
2037 if fd_ut.is_pointer() && ftm_ut.to_rust_string().starts_with('[') =>
2038 {
2039 return ftm_ty;
2040 }
2041 _ => {}
2042 }
2043 fd_ty.or(ftm_ty)
2044 }
2045 ExprKind::Deref(inner) => {
2046 let inner_ut = self.infer_expr_type_unified(inner, info)?;
2047 inner_ut.inner_type().cloned()
2048 }
2049 ExprKind::Index { expr: base, .. } => {
2050 let base_ut = self.infer_expr_type_unified(base, info)?;
2053 base_ut.inner_type().cloned()
2054 }
2055 ExprKind::Binary { op, lhs, rhs } => {
2056 match op {
2057 BinOp::Shl | BinOp::Shr => self.infer_expr_type_unified(lhs, info),
2058 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => {
2059 let lt = self.infer_expr_type_unified(lhs, info);
2060 let rt = self.infer_expr_type_unified(rhs, info);
2061 match (<, &rt) {
2062 (Some(l), Some(r)) => {
2063 let ls = l.to_rust_string();
2064 let rs = r.to_rust_string();
2065 wider_integer_type(&ls, &rs)
2066 .map(|w| UnifiedType::from_rust_str(w))
2067 .or(lt)
2068 }
2069 (Some(_), None) => lt,
2070 (None, Some(_)) => rt,
2071 _ => None,
2072 }
2073 }
2074 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt
2075 | BinOp::Le | BinOp::Ge | BinOp::LogAnd | BinOp::LogOr => {
2076 Some(UnifiedType::Bool)
2077 }
2078 _ => {
2079 if *op == BinOp::Sub {
2082 let lp = self.is_pointer_expr_unified(lhs, info)
2083 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
2084 let rp = self.is_pointer_expr_unified(rhs, info)
2085 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
2086 if lp && rp {
2087 return Some(UnifiedType::Named("isize".to_string()));
2088 }
2089 }
2090 let lt = self.infer_expr_type_unified(lhs, info);
2091 if lt.is_some() { return lt; }
2092 self.infer_expr_type_unified(rhs, info)
2093 }
2094 }
2095 }
2096 ExprKind::BitNot(inner) | ExprKind::UnaryMinus(inner) => self.infer_expr_type_unified(inner, info),
2097 ExprKind::CharLit(_) => Some(UnifiedType::from_rust_str("i8")),
2098 ExprKind::UIntLit(_) => Some(UnifiedType::Int { signed: false, size: crate::unified_type::IntSize::LongLong }),
2099 ExprKind::Sizeof(_) | ExprKind::SizeofType(_) => Some(UnifiedType::Named("usize".to_string())),
2104 ExprKind::Call { func, .. } => {
2105 if let ExprKind::Member { expr: receiver, member, .. } = &func.kind {
2107 let method_name = self.interner.get(*member);
2108 if matches!(method_name, "offset" | "wrapping_add" | "wrapping_sub" | "wrapping_offset") {
2109 return self.infer_expr_type_unified(receiver, info);
2110 }
2111 }
2112 if let ExprKind::Ident(name) = &func.kind {
2113 let func_name = self.interner.get(*name);
2114 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2115 return Some(ret_ut.clone());
2116 }
2117 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2119 if let Some(ty) = macro_info.get_return_type() {
2120 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2121 }
2122 }
2123 if let Some(dict) = self.inline_fn_dict {
2125 if let Some(func_def) = dict.get(*name) {
2126 let base = self.base_type_str_readonly(&func_def.specs.type_specs);
2128 let mut result = base;
2129 let pointer_count = func_def.declarator.derived.iter()
2130 .take_while(|d| !matches!(d, crate::ast::DerivedDecl::Function(_)))
2131 .filter(|d| matches!(d, crate::ast::DerivedDecl::Pointer(_)))
2132 .count();
2133 let is_const_ptr = pointer_count == 1
2134 && func_def.specs.qualifiers.is_const;
2135 for _ in 0..pointer_count {
2136 let prefix = if is_const_ptr { "*const " } else { "*mut " };
2137 result = format!("{}{}", prefix, result);
2138 }
2139 return Some(UnifiedType::from_rust_str(&result));
2140 }
2141 }
2142 }
2143 None
2144 }
2145 ExprKind::MacroCall { name, expanded, .. } => {
2146 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2147 if let Some(ty) = macro_info.get_return_type() {
2148 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2149 }
2150 }
2151 self.infer_expr_type_unified(expanded, info)
2152 }
2153 ExprKind::Conditional { then_expr, else_expr, .. } => {
2154 if is_null_literal(then_expr) {
2155 return self.infer_expr_type_unified(else_expr, info);
2156 }
2157 if is_null_literal(else_expr) {
2158 return self.infer_expr_type_unified(then_expr, info);
2159 }
2160 let tt = self.infer_expr_type_unified(then_expr, info);
2161 let et = self.infer_expr_type_unified(else_expr, info);
2162 match (&tt, &et) {
2163 (Some(t), Some(e)) if t.is_void_pointer() && e.is_concrete_pointer() => et,
2164 (Some(t), Some(e)) if e.is_void_pointer() && t.is_concrete_pointer() => tt,
2165 (Some(_), _) => tt,
2166 (None, _) => et,
2167 }
2168 }
2169 _ => None,
2170 }
2171 }
2172
2173 fn is_pointer_expr_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2175 match &expr.kind {
2176 ExprKind::Ident(name) => {
2177 if let Some(ut) = self.current_param_types.get(name) {
2178 return ut.is_pointer();
2179 }
2180 if let Some(info) = info {
2181 if let Some(constraints) = info.type_env.param_constraints.get(name) {
2182 for c in constraints {
2183 if is_type_repr_pointer(&c.ty) {
2184 return true;
2185 }
2186 }
2187 }
2188 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
2189 for expr_id in expr_ids {
2190 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
2191 for c in constraints {
2192 if is_type_repr_pointer(&c.ty) {
2193 return true;
2194 }
2195 }
2196 }
2197 }
2198 }
2199 }
2200 false
2201 }
2202 ExprKind::Cast { type_name, .. } => {
2203 type_name.declarator.as_ref()
2204 .map(|d| d.derived.iter().any(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer { .. })))
2205 .unwrap_or(false)
2206 }
2207 ExprKind::AddrOf(_) => true,
2208 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => {
2209 let member_str = self.interner.get(*member);
2210 self.field_type_map.get(member_str).is_some_and(|ut| ut.is_pointer())
2211 }
2212 ExprKind::Deref(inner) => {
2213 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
2214 if let Some(derefed) = ut.inner_type() {
2215 return derefed.is_pointer();
2216 }
2217 }
2218 false
2219 }
2220 ExprKind::Call { func, .. } | ExprKind::MacroCall { expanded: func, .. } => {
2221 let check_func = match &expr.kind {
2222 ExprKind::MacroCall { name, .. } => {
2223 if let Some(callee) = self.macro_ctx.macros.get(name) {
2224 for c in &callee.type_env.return_constraints {
2225 if is_type_repr_pointer(&c.ty) { return true; }
2226 }
2227 }
2228 func
2229 }
2230 _ => func,
2231 };
2232 if let ExprKind::Ident(name) = &check_func.kind {
2233 if let Some(callee) = self.macro_ctx.macros.get(name) {
2234 for c in &callee.type_env.return_constraints {
2235 if is_type_repr_pointer(&c.ty) { return true; }
2236 }
2237 }
2238 if let Some(ret_ut) = self.get_callee_return_type(self.interner.get(*name)) {
2239 return ret_ut.is_pointer();
2240 }
2241 }
2242 false
2243 }
2244 ExprKind::Binary { op, lhs, rhs } => {
2245 match op {
2246 BinOp::Add => self.is_pointer_expr_unified(lhs, info) || self.is_pointer_expr_unified(rhs, info),
2247 BinOp::Sub => self.is_pointer_expr_unified(lhs, info) && !self.is_pointer_expr_unified(rhs, info),
2248 _ => false,
2249 }
2250 }
2251 _ => false,
2252 }
2253 }
2254
2255 fn is_option_fn_pointer_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2262 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2266 let member_str = self.interner.get(*member);
2267 if let Some(ut) = self.field_type_map.get(member_str) {
2268 let ty_str = ut.to_rust_string();
2269 if type_str_is_fn_pointer(&ty_str) {
2270 return true;
2271 }
2272 if let Some(dict) = self.rust_decl_dict {
2273 if let Some(alias) = dict.types.get(&ty_str) {
2274 if type_str_is_fn_pointer(&alias.ty) {
2275 return true;
2276 }
2277 }
2278 }
2279 }
2280 }
2281 let Some(ut) = self.infer_expr_type_unified(expr, info) else { return false };
2282 let ty_str = ut.to_rust_string();
2283 if type_str_is_fn_pointer(&ty_str) {
2284 return true;
2285 }
2286 if let Some(dict) = self.rust_decl_dict {
2288 if let Some(alias) = dict.types.get(&ty_str) {
2289 if type_str_is_fn_pointer(&alias.ty) {
2290 return true;
2291 }
2292 }
2293 }
2294 false
2295 }
2296
2297 fn wrap_as_bool_condition(&self, expr: &Expr, expr_str: &str, info: Option<&MacroInferInfo>) -> String {
2299 if self.is_bool_expr_with_dict(expr) {
2300 return expr_str.to_string();
2301 }
2302 if let ExprKind::Ident(name) = &expr.kind {
2304 if let Some(ut) = self.current_param_types.get(name) {
2305 if ut.is_bool() {
2306 return expr_str.to_string();
2307 }
2308 }
2309 }
2310 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2312 let member_str = self.interner.get(*member);
2313 if let Some(ut) = self.field_type_map.get(member_str) {
2314 if ut.is_bool() {
2315 return expr_str.to_string();
2316 }
2317 }
2318 }
2319 if let ExprKind::Call { func, args, .. } = &expr.kind {
2321 if let ExprKind::Ident(name) = &func.kind {
2322 if self.interner.get(*name) == "__builtin_expect" && !args.is_empty() {
2323 return self.wrap_as_bool_condition(&args[0], expr_str, info);
2324 }
2325 }
2326 }
2327 if expr_str.ends_with(" as bool)") || expr_str.ends_with("!= 0)") || expr_str.ends_with(".is_null()") {
2328 return expr_str.to_string();
2329 }
2330 if self.is_option_fn_pointer_expr(expr, info) {
2333 return format!("{}.is_some()", expr_str);
2334 }
2335 if self.is_pointer_expr_unified(expr, info)
2336 || self.infer_expr_type_unified(expr, info).is_some_and(|ut| ut.is_pointer()) {
2337 return format!("!({}).is_null()", expr_str);
2342 }
2343 format!("({} != 0)", strip_outer_parens(expr_str))
2344 }
2345
2346 fn needs_my_perl_for_call(&self, func_name: crate::InternedStr, actual_arg_count: usize) -> bool {
2353 if !self.perl_threaded {
2357 return false;
2358 }
2359 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2360 if callee_info.is_thx_dependent {
2361 let expected_count = callee_info.params.len() + 1;
2363 return actual_arg_count + 1 == expected_count;
2365 }
2366 }
2367 false
2368 }
2369
2370 fn is_static_array_expr(&self, expr: &Expr) -> bool {
2372 if let ExprKind::Ident(name) = &expr.kind {
2373 let name_str = self.interner.get(*name);
2374 self.bindings_info.static_arrays.contains(name_str)
2375 } else {
2376 false
2377 }
2378 }
2379
2380 fn is_array_like_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2388 if self.is_static_array_expr(expr) {
2389 return true;
2390 }
2391 if let ExprKind::Member { expr: base, member }
2393 | ExprKind::PtrMember { expr: base, member } = &expr.kind
2394 {
2395 if let (Some(fd), Some(info)) = (self.fields_dict, info) {
2396 if let Some(constraints) = info.type_env.expr_constraints.get(&base.id) {
2397 if let Some(base_type) = constraints.first().map(|c| &c.ty) {
2398 let struct_name = match &expr.kind {
2399 ExprKind::PtrMember { .. } => base_type.pointee_name(),
2400 _ => base_type.type_name(),
2401 };
2402 if let Some(sn) = struct_name {
2403 if fd.is_flexible_array_field(sn, *member) {
2404 return false;
2405 }
2406 }
2407 }
2408 }
2409 }
2410 }
2411 if let Some(ut) = self.infer_expr_type_unified(expr, info) {
2412 let s = ut.to_rust_string();
2413 if s.starts_with('[') && s.contains(';') {
2414 return true;
2415 }
2416 }
2417 false
2418 }
2419
2420 fn is_bitfield_method(&self, member_name: &str) -> bool {
2424 self.bindings_info.bitfield_methods.values()
2425 .any(|methods| methods.contains(member_name))
2426 }
2427
2428 fn get_callee_generic_params(&self, func_name: InternedStr) -> Option<&HashMap<i32, String>> {
2430 let callee_info = self.macro_ctx.macros.get(&func_name)?;
2431 if callee_info.generic_type_params.is_empty() {
2432 return None;
2433 }
2434 if callee_info.generic_type_params.keys().any(|&k| k >= 0) {
2435 Some(&callee_info.generic_type_params)
2436 } else {
2437 None
2438 }
2439 }
2440
2441 fn is_enum_cast_target(&self, type_name: &crate::ast::TypeName) -> bool {
2443 for spec in &type_name.specs.type_specs {
2444 match spec {
2445 TypeSpec::TypedefName(name) => return self.enum_dict.is_target_enum(*name),
2446 TypeSpec::Enum(_) => return true,
2447 _ => {}
2448 }
2449 }
2450 false
2451 }
2452
2453 fn callee_expects_literal_string(&self, func_name: InternedStr, arg_index: usize) -> bool {
2455 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2456 return callee_info.literal_string_params.contains(&arg_index);
2457 }
2458 false
2459 }
2460
2461 fn get_callee_param_type(&self, func_name: &str, arg_index: usize) -> Option<&UnifiedType> {
2463 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2464 f.params.get(arg_index).map(|p| &p.uty)
2465 })
2466 }
2467
2468 fn get_callee_param_type_extended(&mut self, func_name: &str, arg_index: usize) -> Option<UnifiedType> {
2470 if let Some(ut) = libc_fn_param_type(func_name, arg_index) {
2474 return Some(ut);
2475 }
2476 if let Some(ut) = self.get_callee_param_type(func_name, arg_index) {
2478 return Some(ut.clone());
2479 }
2480 if let Some(interned) = self.interner.lookup(func_name) {
2481 if let Some(dict) = self.inline_fn_dict {
2483 if let Some(func_def) = dict.get(interned) {
2484 for d in &func_def.declarator.derived {
2485 if let DerivedDecl::Function(param_list) = d {
2486 if let Some(param) = param_list.params.get(arg_index) {
2487 let ty = self.param_type_only(param);
2488 return Some(UnifiedType::from_rust_str(&ty));
2489 }
2490 break;
2491 }
2492 }
2493 }
2494 }
2495 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2497 let macro_param_idx = if self.perl_threaded && macro_info.is_thx_dependent {
2500 if arg_index == 0 {
2501 return Some(UnifiedType::from_rust_str("*mut PerlInterpreter"));
2502 }
2503 arg_index - 1
2504 } else {
2505 arg_index
2506 };
2507 if let Some(param) = macro_info.params.get(macro_param_idx) {
2508 if let Some(mut ty) = best_constraint_for_macro_param(macro_info, param) {
2512 let should_be_const = macro_info
2515 .const_pointer_positions
2516 .contains(¯o_param_idx);
2517 if should_be_const {
2518 ty.make_outer_pointer_const();
2519 } else if ty.has_outer_pointer() {
2520 ty.make_outer_pointer_mut();
2521 }
2522 let rust_ty = ty.to_rust_string(self.interner);
2523 return Some(UnifiedType::from_rust_str(&rust_ty));
2524 }
2525 }
2526 }
2527 }
2528 None
2529 }
2530
2531 fn callee_param_is_bool(&self, func_name: &str, arg_index: usize) -> bool {
2533 if let Some(param_ut) = self.get_callee_param_type(func_name, arg_index) {
2535 return param_ut.is_bool();
2536 }
2537 if let Some(interned) = self.interner.lookup(func_name) {
2539 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2540 let macro_arg_index = if self.perl_threaded
2543 && macro_info.is_thx_dependent
2544 && arg_index > 0
2545 {
2546 arg_index - 1
2547 } else {
2548 arg_index
2549 };
2550 if let Some(param) = macro_info.params.get(macro_arg_index) {
2551 if let Some(expr_ids) = macro_info.type_env.param_to_exprs.get(¶m.name) {
2553 for expr_id in expr_ids {
2554 if let Some(constraints) = macro_info.type_env.expr_constraints.get(expr_id) {
2555 for c in constraints {
2556 let rust_ty = c.ty.to_rust_string(self.interner);
2557 if rust_ty == "bool" {
2558 return true;
2559 }
2560 }
2561 }
2562 }
2563 }
2564 }
2565 }
2566 if let Some(dict) = self.inline_fn_dict {
2568 if let Some(func_def) = dict.get(interned) {
2569 for d in &func_def.declarator.derived {
2570 if let DerivedDecl::Function(param_list) = d {
2571 if let Some(param) = param_list.params.get(arg_index) {
2572 let has_bool = param.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2573 let has_pointer = param.declarator.as_ref().map_or(false, |decl| {
2574 decl.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)))
2575 });
2576 if has_bool && !has_pointer {
2577 return true;
2578 }
2579 }
2580 break;
2581 }
2582 }
2583 }
2584 }
2585 }
2586 false
2587 }
2588
2589 fn get_callee_return_type(&self, func_name: &str) -> Option<&UnifiedType> {
2591 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2592 f.uret_ty.as_ref()
2593 })
2594 }
2595
2596 fn is_rust_enum_type(&self, ut: &UnifiedType) -> bool {
2600 if let UnifiedType::Named(name) = ut {
2601 if let Some(dict) = self.rust_decl_dict {
2602 return dict.enums.contains(name.as_str());
2603 }
2604 }
2605 false
2606 }
2607
2608 fn is_bool_expr_with_dict(&self, expr: &Expr) -> bool {
2610 if is_boolean_expr_recursive(expr, self.interner) {
2611 return true;
2612 }
2613 if let ExprKind::Index { expr: base, .. } = &expr.kind {
2615 if let ExprKind::Ident(name) = &base.kind {
2616 if let Some(dict) = self.rust_decl_dict {
2617 let name_str = self.interner.get(*name);
2618 if let Some(c) = dict.consts.get(name_str) {
2619 if let Some(inner) = c.uty.inner_type() {
2620 if inner.is_bool() {
2621 return true;
2622 }
2623 }
2624 }
2625 if dict.statics.contains(name_str) && name_str.starts_with("PL_valid_types_") {
2627 return true;
2628 }
2629 }
2630 }
2631 }
2632 if let ExprKind::Ident(name) = &expr.kind {
2634 if let Some(ut) = self.current_param_types.get(name) {
2635 if ut.is_bool() {
2636 return true;
2637 }
2638 }
2639 }
2640 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2642 let member_str = self.interner.get(*member);
2643 if let Some(ut) = self.field_type_map.get(member_str) {
2644 if ut.is_bool() {
2645 return true;
2646 }
2647 }
2648 }
2649 if let ExprKind::Call { func, .. } = &expr.kind {
2651 if let ExprKind::Ident(name) = &func.kind {
2652 if self.bool_return_macros.contains(name) {
2654 return true;
2655 }
2656 let func_name = self.interner.get(*name);
2657 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2659 return ret_ut.is_bool();
2660 }
2661 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2663 if let Some(ty) = macro_info.get_return_type() {
2664 let rust_ty = ty.to_rust_string(self.interner);
2665 return rust_ty == "bool";
2666 }
2667 }
2668 if let Some(dict) = self.inline_fn_dict {
2670 if let Some(func_def) = dict.get(*name) {
2671 let has_bool_return = func_def.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2672 let has_return_pointer = func_def.declarator.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)));
2673 if has_bool_return && !has_return_pointer {
2674 return true;
2675 }
2676 }
2677 }
2678 }
2679 }
2680 if let ExprKind::MacroCall { name, .. } = &expr.kind {
2682 if self.bool_return_macros.contains(name) {
2683 return true;
2684 }
2685 }
2686 false
2687 }
2688
2689 fn find_literal_string_ident<'b>(&self, expr: &'b Expr) -> Option<&'b InternedStr> {
2692 match &expr.kind {
2693 ExprKind::Ident(name) if self.current_literal_string_params.contains(name) => {
2694 Some(name)
2695 }
2696 ExprKind::Call { func, args } if args.len() == 1 => {
2697 if let ExprKind::Ident(fname) = &func.kind {
2699 let func_name = self.interner.get(*fname);
2700 if func_name == "ASSERT_IS_LITERAL"
2701 || func_name == "ASSERT_IS_PTR"
2702 || func_name == "ASSERT_NOT_PTR"
2703 {
2704 return self.find_literal_string_ident(&args[0]);
2705 }
2706 }
2707 None
2708 }
2709 _ => None,
2710 }
2711 }
2712
2713
2714 fn should_emit_as_macro_call(&self, name: crate::InternedStr) -> bool {
2721 if let Some(info) = self.macro_ctx.macros.get(&name) {
2723 return info.is_parseable() && !info.calls_unavailable;
2725 }
2726 false
2727 }
2728
2729 fn unknown_marker(&mut self) -> &'static str {
2731 self.incomplete_count += 1;
2732 "/* unknown */"
2733 }
2734
2735 fn todo_marker(&mut self, msg: &str) -> String {
2737 self.incomplete_count += 1;
2738 format!("/* TODO: {} */", msg)
2739 }
2740
2741 fn type_marker(&mut self) -> &'static str {
2743 self.incomplete_count += 1;
2744 "/* type */"
2745 }
2746
2747 fn collect_decl_names(&mut self, decl: &Declaration) {
2750 let base_type = self.decl_specs_to_rust(&decl.specs);
2751 for init_decl in &decl.declarators {
2752 if let Some(name) = init_decl.declarator.name {
2753 self.current_local_names.insert(name);
2754 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2755 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2756 }
2757 }
2758 }
2759
2760 fn collect_local_names_recursive(&mut self, body: &CompoundStmt) {
2766 for item in &body.items {
2767 self.collect_local_names_from_block_item(item);
2768 }
2769 }
2770
2771 fn collect_local_names_from_block_item(&mut self, item: &BlockItem) {
2772 match item {
2773 BlockItem::Decl(d) => self.collect_decl_names(d),
2774 BlockItem::Stmt(s) => self.collect_local_names_from_stmt(s),
2775 }
2776 }
2777
2778 fn collect_local_names_from_stmt(&mut self, stmt: &Stmt) {
2779 match stmt {
2780 Stmt::Compound(c) => self.collect_local_names_recursive(c),
2781 Stmt::If { then_stmt, else_stmt, cond, .. } => {
2782 self.collect_local_names_from_expr(cond);
2783 self.collect_local_names_from_stmt(then_stmt);
2784 if let Some(es) = else_stmt {
2785 self.collect_local_names_from_stmt(es);
2786 }
2787 }
2788 Stmt::Switch { body, expr, .. } => {
2789 self.collect_local_names_from_expr(expr);
2790 self.collect_local_names_from_stmt(body);
2791 }
2792 Stmt::While { body, cond, .. } => {
2793 self.collect_local_names_from_expr(cond);
2794 self.collect_local_names_from_stmt(body);
2795 }
2796 Stmt::DoWhile { body, cond, .. } => {
2797 self.collect_local_names_from_stmt(body);
2798 self.collect_local_names_from_expr(cond);
2799 }
2800 Stmt::For { init, cond, step, body, .. } => {
2801 if let Some(i) = init {
2802 match i {
2803 ForInit::Decl(d) => self.collect_decl_names(d),
2804 ForInit::Expr(e) => self.collect_local_names_from_expr(e),
2805 }
2806 }
2807 if let Some(c) = cond { self.collect_local_names_from_expr(c); }
2808 if let Some(s) = step { self.collect_local_names_from_expr(s); }
2809 self.collect_local_names_from_stmt(body);
2810 }
2811 Stmt::Expr(Some(e), _) => self.collect_local_names_from_expr(e),
2812 Stmt::Return(Some(e), _) => self.collect_local_names_from_expr(e),
2813 Stmt::Label { stmt, .. } | Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => {
2814 self.collect_local_names_from_stmt(stmt);
2815 }
2816 _ => {}
2817 }
2818 }
2819
2820 fn collect_local_names_from_expr(&mut self, expr: &Expr) {
2821 if let ExprKind::StmtExpr(c) = &expr.kind {
2822 self.collect_local_names_recursive(c);
2823 }
2824 match &expr.kind {
2827 ExprKind::Binary { lhs, rhs, .. }
2828 | ExprKind::Assign { lhs, rhs, .. }
2829 | ExprKind::Comma { lhs, rhs } => {
2830 self.collect_local_names_from_expr(lhs);
2831 self.collect_local_names_from_expr(rhs);
2832 }
2833 ExprKind::Conditional { cond, then_expr, else_expr } => {
2834 self.collect_local_names_from_expr(cond);
2835 self.collect_local_names_from_expr(then_expr);
2836 self.collect_local_names_from_expr(else_expr);
2837 }
2838 ExprKind::Cast { expr: e, .. }
2839 | ExprKind::AddrOf(e) | ExprKind::Deref(e)
2840 | ExprKind::UnaryPlus(e) | ExprKind::UnaryMinus(e)
2841 | ExprKind::BitNot(e) | ExprKind::LogNot(e)
2842 | ExprKind::PreInc(e) | ExprKind::PreDec(e)
2843 | ExprKind::PostInc(e) | ExprKind::PostDec(e)
2844 | ExprKind::Sizeof(e)
2845 | ExprKind::Member { expr: e, .. } | ExprKind::PtrMember { expr: e, .. } => {
2846 self.collect_local_names_from_expr(e);
2847 }
2848 ExprKind::Call { func, args } => {
2849 self.collect_local_names_from_expr(func);
2850 for a in args { self.collect_local_names_from_expr(a); }
2851 }
2852 ExprKind::Index { expr: e, index } => {
2853 self.collect_local_names_from_expr(e);
2854 self.collect_local_names_from_expr(index);
2855 }
2856 _ => {}
2857 }
2858 }
2859
2860 fn collect_decl_types(&mut self, decl: &Declaration) {
2863 let base_type = self.decl_specs_to_rust(&decl.specs);
2864 for init_decl in &decl.declarators {
2865 if let Some(name) = init_decl.declarator.name {
2866 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2867 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2868 }
2869 }
2870 }
2871
2872 fn writeln(&mut self, s: &str) {
2874 self.buffer.push_str(s);
2875 self.buffer.push('\n');
2876 }
2877
2878 fn into_generated_code(self) -> GeneratedCode {
2880 GeneratedCode {
2881 code: self.buffer,
2882 incomplete_count: self.incomplete_count,
2883 unresolved_names: self.unresolved_names,
2884 used_libc_fns: self.used_libc_fns,
2885 codegen_errors: self.codegen_errors,
2886 }
2887 }
2888
2889 pub fn generate_macro(mut self, info: &MacroInferInfo) -> GeneratedCode {
2891 let name_str = self.interner.get(info.name);
2892
2893 for p in &info.params {
2895 self.current_local_names.insert(p.name);
2896 }
2897
2898 self.current_type_param_map = info.generic_type_params.iter()
2900 .filter(|(idx, _)| **idx >= 0)
2901 .filter_map(|(idx, generic_name)| {
2902 info.params.get(*idx as usize).map(|p| (p.name, generic_name.clone()))
2903 })
2904 .collect();
2905
2906 for (name, _) in &self.current_type_param_map {
2909 self.current_local_names.remove(name);
2910 }
2911
2912 self.current_literal_string_params = info.literal_string_params.iter()
2914 .filter_map(|&idx| info.params.get(idx).map(|p| p.name))
2915 .collect();
2916
2917 let generic_clause = self.build_generic_clause(info);
2919
2920 let params_with_types = self.build_param_list(info);
2923
2924 let return_type = self.get_return_type(info);
2926 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
2927
2928 if self.dump_types_for.as_deref() == Some(name_str) {
2930 self.dump_type_info(name_str, info, ¶ms_with_types, &return_type);
2931 }
2932
2933 let thx_param = if self.perl_threaded && info.is_thx_dependent {
2936 "my_perl: *mut PerlInterpreter"
2937 } else {
2938 ""
2939 };
2940
2941 let params_str = if thx_param.is_empty() {
2943 params_with_types.clone()
2944 } else if params_with_types.is_empty() {
2945 thx_param.to_string()
2946 } else {
2947 format!("{}, {}", thx_param, params_with_types)
2948 };
2949
2950 self.dump_ast_comment_for_expr(name_str, &info.parse_result);
2952
2953 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
2955 let generic_info = if !generic_clause.is_empty() { " [generic]" } else { "" };
2956 self.writeln(&format!("/// {}{}{} - macro function", name_str, thx_info, generic_info));
2957 self.writeln("#[inline]");
2958 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
2959
2960 self.writeln(&format!("pub unsafe fn {}{}({}) -> {} {{", name_str, generic_clause, params_str, return_type));
2962
2963 let needs_unsafe = info.has_unsafe_ops();
2965 let body_indent = if needs_unsafe { " " } else { " " };
2966
2967 if needs_unsafe {
2968 self.writeln(" unsafe {");
2969 }
2970
2971 match &info.parse_result {
2972 ParseResult::Expression(expr) => {
2973 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
2974 let mut syn_expr = self.build_syn_expr_with_type_hint(expr, Some(info), type_hint.as_deref());
2975
2976 if self.current_return_type.as_ref().is_some_and(|ut| ut.is_void()) {
2977 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2978 self.writeln(&format!("{}{};", body_indent, s));
2979 } else if self.current_return_type.as_ref().is_some_and(|ut| ut.is_bool())
2980 && !self.is_bool_expr_with_dict(expr)
2981 && !crate::syn_codegen::is_bool_syn_expr(&syn_expr) {
2982 if self.is_pointer_expr_unified(expr, Some(info))
2983 || self.infer_expr_type_unified(expr, Some(info)).is_some_and(|ut| ut.is_pointer()) {
2984 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2985 self.writeln(&format!("{}!({}).is_null()", body_indent, s));
2988 } else {
2989 syn_expr = crate::syn_codegen::wrap_as_bool(syn_expr);
2990 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2991 self.writeln(&format!("{}{}", body_indent, s));
2992 }
2993 } else {
2994 syn_expr = self.cast_return_syn_expr_if_needed(expr, Some(info), syn_expr);
2995 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2996 self.writeln(&format!("{}{}", body_indent, s));
2997 }
2998 }
2999 ParseResult::Statement(block_items) => {
3000 for item in block_items {
3001 if let BlockItem::Stmt(stmt) = item {
3002 let rust_stmt = self.stmt_to_rust(stmt, info);
3003 self.writeln(&format!("{}{}", body_indent, rust_stmt));
3004 }
3005 }
3006 }
3007 ParseResult::Unparseable(_) => {
3008 self.writeln(&format!("{}unimplemented!()", body_indent));
3009 }
3010 }
3011
3012 if needs_unsafe {
3013 self.writeln(" }");
3014 }
3015
3016 self.writeln("}");
3017 self.writeln("");
3018
3019 self.into_generated_code()
3020 }
3021
3022 fn build_generic_clause(&self, info: &MacroInferInfo) -> String {
3024 if info.generic_type_params.is_empty() {
3025 return String::new();
3026 }
3027
3028 let mut params: Vec<&String> = info.generic_type_params.values().collect();
3030 params.sort();
3031 params.dedup();
3032
3033 format!("<{}>", params.iter().map(|s| s.as_str()).collect::<Vec<_>>().join(", "))
3034 }
3035
3036 fn build_param_list(&mut self, info: &MacroInferInfo) -> String {
3040 let mut_params = collect_mut_params(&info.parse_result, &info.params);
3041 let mut parts = Vec::new();
3042 for (i, p) in info.params.iter().enumerate() {
3043 if info.generic_type_params.contains_key(&(i as i32)) {
3044 continue;
3045 }
3046 let name = escape_rust_keyword(self.interner.get(p.name));
3047 let ty = self.get_param_type(p, info, i);
3048 self.current_param_types.insert(p.name, UnifiedType::from_rust_str(&ty));
3050 let mut_prefix = if mut_params.contains(&p.name) { "mut " } else { "" };
3051 parts.push(format!("{}{}: {}", mut_prefix, name, ty));
3052 }
3053 parts.join(", ")
3054 }
3055
3056 fn get_param_type(&mut self, param: &MacroParam, info: &MacroInferInfo, param_index: usize) -> String {
3058 if let Some(generic_name) = info.generic_type_params.get(&(param_index as i32)) {
3060 return generic_name.clone();
3061 }
3062
3063 if info.literal_string_params.contains(¶m_index) {
3065 return "&str".to_string();
3066 }
3067
3068 let should_be_const = self.const_pointer_positions.contains(¶m_index);
3069
3070 if let Some(mut ty) = best_constraint_for_macro_param(info, param) {
3071 if should_be_const {
3072 ty.make_outer_pointer_const();
3073 } else if ty.has_outer_pointer() {
3074 ty.make_outer_pointer_mut();
3076 }
3077 return self.type_repr_to_rust(&ty);
3078 }
3079
3080 self.unknown_marker().to_string()
3081 }
3082
3083 fn get_return_type(&mut self, info: &MacroInferInfo) -> String {
3089 if let Some(generic_name) = info.generic_type_params.get(&-1) {
3091 return generic_name.clone();
3092 }
3093
3094 if self.is_bool_return {
3096 return "bool".to_string();
3097 }
3098
3099 match &info.parse_result {
3100 ParseResult::Expression(expr) => {
3101 if let Some(ty) = info.get_return_type() {
3102 let mut ty_str = self.type_repr_to_rust(ty);
3103 if ty_str != "()" {
3104 if ty_str.contains("*mut") {
3106 if let Some(expr_ut) = self.infer_expr_type(expr, info) {
3107 if expr_ut.is_const_pointer() {
3108 ty_str = ty_str.replace("*mut", "*const");
3109 }
3110 }
3111 }
3112 return ty_str;
3113 }
3114 if let Some(ut) = self.infer_expr_type(expr, info) {
3118 let s = ut.to_rust_string();
3119 if s != "()" {
3120 return s;
3121 }
3122 }
3123 return ty_str;
3125 }
3126 self.unknown_marker().to_string()
3127 }
3128 ParseResult::Statement(_) => "()".to_string(),
3129 ParseResult::Unparseable(_) => "()".to_string(),
3130 }
3131 }
3132
3133 fn type_repr_to_rust(&mut self, ty: &crate::type_repr::TypeRepr) -> String {
3137 let result = ty.to_rust_string(self.interner);
3138 let result = self.substitute_type_params(&result);
3139 if result.contains("/*") {
3140 self.incomplete_count += 1;
3141 }
3142 result
3143 }
3144
3145 fn substitute_type_params(&self, type_str: &str) -> String {
3147 if self.current_type_param_map.is_empty() {
3148 return type_str.to_string();
3149 }
3150 let mut result = type_str.to_string();
3151 for (param_name, generic_name) in &self.current_type_param_map {
3152 let name_str = self.interner.get(*param_name);
3153 result = replace_word(&result, name_str, generic_name);
3155 }
3156 result
3157 }
3158
3159 fn detect_mutable_ptr_pattern<'b>(&self, compound: &'b CompoundStmt) -> Option<&'b Expr> {
3164 if compound.items.len() != 2 {
3166 return None;
3167 }
3168
3169 let decl = match &compound.items[0] {
3171 BlockItem::Decl(d) => d,
3172 _ => return None,
3173 };
3174
3175 if decl.declarators.len() != 1 {
3177 return None;
3178 }
3179 let init_decl = &decl.declarators[0];
3180 let declared_name = init_decl.declarator.name?;
3181 let init = init_decl.init.as_ref()?;
3182
3183 let init_expr = match init {
3185 Initializer::Expr(e) => e.as_ref(),
3186 _ => return None,
3187 };
3188
3189 let last_expr = match &compound.items[1] {
3191 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => e,
3192 _ => return None,
3193 };
3194
3195 if let ExprKind::Ident(name) = &last_expr.kind {
3197 if *name == declared_name {
3198 return Some(init_expr);
3199 }
3200 }
3201
3202 None
3203 }
3204
3205 fn maybe_decay_flex_array(
3216 &self,
3217 access: syn::Expr,
3218 base: &Expr,
3219 member: InternedStr,
3220 info: Option<&MacroInferInfo>,
3221 is_ptr_member: bool,
3222 ) -> syn::Expr {
3223 let Some(fd) = self.fields_dict else { return access; };
3224 let Some(info) = info else { return access; };
3225 let Some(constraints) = info.type_env.expr_constraints.get(&base.id) else {
3226 return access;
3227 };
3228 let Some(base_type) = constraints.first().map(|c| &c.ty) else {
3229 return access;
3230 };
3231 let struct_name = if is_ptr_member {
3232 base_type.pointee_name()
3233 } else {
3234 base_type.type_name()
3235 };
3236 let Some(struct_name) = struct_name else { return access; };
3237 let Some(elem) = fd.flexible_array_element(struct_name, member) else {
3238 return access;
3239 };
3240 let elem_str = elem.to_rust_string(self.interner);
3242 let target_ty_str = format!("*mut {}", elem_str);
3243 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3244 attrs: vec![],
3245 and_token: Default::default(),
3246 raw: Default::default(),
3247 mutability: syn::PointerMutability::Const(Default::default()),
3248 expr: Box::new(access),
3249 });
3250 crate::syn_codegen::insert_cast(raw_const, crate::syn_codegen::parse_type(&target_ty_str))
3251 }
3252
3253 fn try_inline_call_for_addrof(&self, inner: &Expr) -> Option<Expr> {
3262 let (callee_id, args) = match &inner.kind {
3263 ExprKind::Call { func, args } => match &func.kind {
3264 ExprKind::Ident(name) => (*name, args),
3265 _ => return None,
3266 },
3267 _ => return None,
3268 };
3269
3270 let callee_info = self.macro_ctx.macros.get(&callee_id)?;
3271 let body = match &callee_info.parse_result {
3272 ParseResult::Expression(e) => e,
3273 _ => return None,
3274 };
3275
3276 if callee_info.is_thx_dependent {
3278 return None;
3279 }
3280 if callee_info.params.len() != args.len() {
3281 return None;
3282 }
3283
3284 let mut subs: HashMap<InternedStr, &Expr> = HashMap::new();
3286 for (param, arg) in callee_info.params.iter().zip(args.iter()) {
3287 subs.insert(param.name, arg);
3288 }
3289
3290 let mut inlined = (**body).clone();
3291 substitute_idents(&mut inlined, &subs);
3292 Some(inlined)
3293 }
3294
3295 fn build_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
3300 use crate::syn_codegen::*;
3301
3302 match &expr.kind {
3303 ExprKind::Ident(name) => {
3304 if let Some(subst) = self.param_substitutions.get(name) {
3306 return syn::parse_str(subst).unwrap_or_else(|_| int_lit(0));
3308 }
3309 let name_str = self.interner.get(*name);
3310 if LIBC_FUNCTIONS.contains(&name_str) {
3312 self.used_libc_fns.insert(name_str.to_string());
3313 }
3314 if !self.current_local_names.contains(name)
3316 && !self.enum_dict.is_enum_variant(*name)
3317 && !self.known_symbols.contains(name_str)
3318 {
3319 let s = name_str.to_string();
3320 if !self.unresolved_names.contains(&s) {
3321 self.unresolved_names.push(s);
3322 }
3323 }
3324 if name_str == "true" || name_str == "false" {
3326 return syn::Expr::Lit(syn::ExprLit {
3327 attrs: vec![],
3328 lit: syn::Lit::Bool(syn::LitBool {
3329 value: name_str == "true",
3330 span: proc_macro2::Span::call_site(),
3331 }),
3332 });
3333 }
3334 let escaped = escape_rust_keyword(name_str);
3335 if self.bindings_info.static_arrays.contains(name_str) {
3350 let elem = self.bindings_info.static_array_element_type(name_str)
3351 .unwrap_or_else(|| "u8".to_string());
3352 return syn::parse_str(&format!(
3353 "((&raw const {}) as *const {})",
3354 escaped, elem
3355 ))
3356 .unwrap_or_else(|_| int_lit(0));
3357 }
3358 syn::Expr::Path(syn::ExprPath {
3359 attrs: vec![],
3360 qself: None,
3361 path: ident(&escaped).into(),
3362 })
3363 }
3364 ExprKind::IntLit(n) => int_lit(*n),
3365 ExprKind::UIntLit(n) => {
3366 let lit = syn::LitInt::new(&format!("{}u64", n), proc_macro2::Span::call_site());
3367 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Int(lit) })
3368 }
3369 ExprKind::FloatLit(f) => {
3370 let lit = syn::LitFloat::new(&format!("{}", f), proc_macro2::Span::call_site());
3371 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Float(lit) })
3372 }
3373 ExprKind::CharLit(c) => {
3374 let s = if c.is_ascii() {
3375 format!("b'{}' as i8", escape_char(*c))
3376 } else {
3377 format!("0x{:02x}u8 as i8", c)
3378 };
3379 syn::parse_str(&s).unwrap_or_else(|_| int_lit(0))
3380 }
3381 ExprKind::StringLit(s) => {
3382 syn::parse_str(&format!("c\"{}\"", escape_string(s)))
3383 .unwrap_or_else(|_| int_lit(0))
3384 }
3385 ExprKind::Deref(inner) => {
3386 let e = self.build_syn_expr(inner, info);
3387 deref(e)
3388 }
3389 ExprKind::AddrOf(inner) => {
3390 if let Some(inlined) = self.try_inline_call_for_addrof(inner) {
3396 let e = self.build_syn_expr(&inlined, info);
3397 return addr_of_mut(e);
3398 }
3399 let e = self.build_syn_expr(inner, info);
3400 addr_of_mut(e)
3401 }
3402 ExprKind::UnaryPlus(inner) => {
3403 self.build_syn_expr(inner, info)
3404 }
3405 ExprKind::BitNot(inner) => {
3406 let e = self.build_syn_expr(inner, info);
3407 syn::Expr::Unary(syn::ExprUnary {
3408 attrs: vec![],
3409 op: syn::UnOp::Not(Default::default()),
3410 expr: Box::new(e),
3411 })
3412 }
3413 ExprKind::Member { expr: base, member } => {
3414 let e = self.build_syn_expr(base, info);
3415 let m = self.interner.get(*member);
3416 if self.is_bitfield_method(m) {
3417 syn::Expr::MethodCall(syn::ExprMethodCall {
3419 attrs: vec![],
3420 receiver: Box::new(e),
3421 dot_token: Default::default(),
3422 method: ident(m),
3423 turbofish: None,
3424 paren_token: Default::default(),
3425 args: syn::punctuated::Punctuated::new(),
3426 })
3427 } else {
3428 let access = field_access(e, m);
3429 self.maybe_decay_flex_array(access, base, *member, info, false)
3430 }
3431 }
3432 ExprKind::PtrMember { expr: base, member } => {
3433 let e = self.build_syn_expr(base, info);
3434 let m = self.interner.get(*member);
3435 let derefed = deref(e);
3436 if self.is_bitfield_method(m) {
3437 syn::Expr::MethodCall(syn::ExprMethodCall {
3438 attrs: vec![],
3439 receiver: Box::new(derefed),
3440 dot_token: Default::default(),
3441 method: ident(m),
3442 turbofish: None,
3443 paren_token: Default::default(),
3444 args: syn::punctuated::Punctuated::new(),
3445 })
3446 } else {
3447 let access = field_access(derefed, m);
3448 self.maybe_decay_flex_array(access, base, *member, info, true)
3449 }
3450 }
3451 ExprKind::Comma { lhs, rhs } => {
3452 let l = self.build_syn_expr(lhs, info);
3453 let r = self.build_syn_expr(rhs, info);
3454 if expr_yields_value_for_stmt_use(&l) {
3466 let l_str = expr_to_string(&l);
3467 let r_str = expr_to_string(&r);
3468 syn::parse_str(&format!("{{ let _ = {}; {} }}", l_str, r_str))
3469 .unwrap_or_else(|_| int_lit(0))
3470 } else {
3471 syn::Expr::Block(syn::ExprBlock {
3472 attrs: vec![],
3473 label: None,
3474 block: syn::Block {
3475 brace_token: Default::default(),
3476 stmts: vec![
3477 syn::Stmt::Expr(l, Some(Default::default())),
3478 syn::Stmt::Expr(r, None),
3479 ],
3480 },
3481 })
3482 }
3483 }
3484 ExprKind::UnaryMinus(inner) => {
3485 let e = self.build_syn_expr(inner, info);
3486 let e_str = expr_to_string(&e);
3488 if is_unsigned_cast_expr(&e_str) {
3489 return syn::parse_str(&format!("({}).wrapping_neg()", e_str.trim_start_matches('-')))
3490 .unwrap_or_else(|_| int_lit(0));
3491 }
3492 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
3493 let ts = ut.to_rust_string();
3494 if matches!(normalize_integer_type(&ts), Some("usize" | "u8" | "u16" | "u32" | "u64")) {
3495 self.codegen_errors.push(format!("cannot negate unsigned type: -({}: {})", e_str, ts));
3496 }
3497 }
3498 syn::Expr::Unary(syn::ExprUnary {
3499 attrs: vec![],
3500 op: syn::UnOp::Neg(Default::default()),
3501 expr: Box::new(e),
3502 })
3503 }
3504 ExprKind::LogNot(inner) => {
3505 if matches!(&inner.kind, ExprKind::StringLit(_)) {
3507 return syn::parse_str("false").unwrap_or_else(|_| int_lit(0));
3508 }
3509 let e = self.build_syn_expr(inner, info);
3510 if !self.is_bool_expr_with_dict(inner)
3511 && (self.is_pointer_expr_unified(inner, info)
3512 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()))
3513 {
3514 return syn::Expr::MethodCall(syn::ExprMethodCall {
3519 attrs: vec![],
3520 receiver: Box::new(e),
3521 dot_token: Default::default(),
3522 method: ident("is_null"),
3523 turbofish: None,
3524 paren_token: Default::default(),
3525 args: syn::punctuated::Punctuated::new(),
3526 });
3527 }
3528 let bool_e = if self.is_bool_expr_with_dict(inner) {
3529 e
3530 } else {
3531 wrap_as_bool(e)
3533 };
3534 syn::Expr::Unary(syn::ExprUnary {
3535 attrs: vec![],
3536 op: syn::UnOp::Not(Default::default()),
3537 expr: Box::new(bool_e),
3538 })
3539 }
3540 ExprKind::Cast { type_name, expr: inner } => {
3541 let t = self.type_name_to_rust(type_name);
3542 if is_unsigned_integer_target(&t) {
3546 if let ExprKind::UnaryMinus(minus_inner) = &inner.kind {
3547 if matches!(&minus_inner.kind,
3548 ExprKind::IntLit(1) | ExprKind::UIntLit(1))
3549 {
3550 return syn::parse_str(&format!("{}::MAX", t))
3551 .unwrap_or_else(|_| int_lit(0));
3552 }
3553 }
3554 }
3555 if (t.starts_with("*mut ") || t.starts_with("*const "))
3562 && matches!(&inner.kind, ExprKind::AddrOf(_))
3563 {
3564 if let ExprKind::AddrOf(addrof_inner) = &inner.kind {
3565 let inlined_owned;
3567 let inner_to_build: &Expr =
3568 if let Some(inlined) = self.try_inline_call_for_addrof(addrof_inner) {
3569 inlined_owned = inlined;
3570 &inlined_owned
3571 } else {
3572 addrof_inner
3573 };
3574 let inner_e = self.build_syn_expr(inner_to_build, info);
3575 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3576 attrs: vec![],
3577 and_token: Default::default(),
3578 raw: Default::default(),
3579 mutability: syn::PointerMutability::Const(Default::default()),
3580 expr: Box::new(inner_e),
3581 });
3582 return insert_cast(raw_const, parse_type(&t));
3583 }
3584 }
3585 let e = self.build_syn_expr(inner, info);
3586 if t == "()" {
3587 let e_str = expr_to_string(&e);
3594 return syn::parse_str(&format!("{{ let _ = {}; }}", e_str))
3595 .unwrap_or_else(|_| int_lit(0));
3596 }
3597 if t == "bool" {
3598 if self.is_bool_expr_with_dict(inner) {
3600 return e;
3601 }
3602 if self.is_pointer_expr_unified(inner, info)
3603 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()) {
3604 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3606 attrs: vec![],
3607 receiver: Box::new(e),
3608 dot_token: Default::default(),
3609 method: ident("is_null"),
3610 turbofish: None,
3611 paren_token: Default::default(),
3612 args: syn::punctuated::Punctuated::new(),
3613 });
3614 return syn::Expr::Unary(syn::ExprUnary {
3615 attrs: vec![],
3616 op: syn::UnOp::Not(Default::default()),
3617 expr: Box::new(is_null),
3618 });
3619 }
3620 return wrap_as_bool(e);
3621 }
3622 if self.is_enum_cast_target(type_name) {
3623 let e_str = expr_to_string(&e);
3625 return syn::parse_str(&format!("std::mem::transmute::<_, {}>({})", t, e_str))
3626 .unwrap_or_else(|_| int_lit(0));
3627 }
3628 insert_cast(e, parse_type(&t))
3629 }
3630 ExprKind::Sizeof(inner) => {
3631 if let ExprKind::Ident(name) = &inner.kind {
3633 if self.current_literal_string_params.contains(name) {
3634 let param = escape_rust_keyword(self.interner.get(*name));
3635 return syn::parse_str(&format!("({}.len() + 1)", param))
3636 .unwrap_or_else(|_| int_lit(0));
3637 }
3638 }
3639 let e = self.build_syn_expr(inner, info);
3640 let e_str = expr_to_string(&e);
3641 syn::parse_str(&format!("std::mem::size_of_val(&({}))", e_str))
3646 .unwrap_or_else(|_| int_lit(0))
3647 }
3648 ExprKind::SizeofType(type_name) => {
3649 let t = self.type_name_to_rust(type_name);
3650 syn::parse_str(&format!("std::mem::size_of::<{}>()", t))
3651 .unwrap_or_else(|_| int_lit(0))
3652 }
3653 ExprKind::Index { expr: base, index } => {
3654 use crate::syn_codegen::*;
3655 let i = self.build_syn_expr(index, info);
3656 let i_isize = cast_syn_expr(i, "isize");
3657 let base_expr: syn::Expr = if self.is_array_like_expr(base, info) {
3658 let raw_ptr_expr: syn::Expr = if let ExprKind::Ident(n) = &base.kind {
3664 let name_str = self.interner.get(*n);
3665 let escaped = escape_rust_keyword(name_str);
3666 if self.bindings_info.static_arrays.contains(name_str) {
3667 let elem = self.bindings_info
3668 .static_array_element_type(name_str)
3669 .unwrap_or_else(|| "u8".to_string());
3670 syn::parse_str(&format!(
3671 "((&raw const {}) as *const {})",
3672 escaped, elem
3673 ))
3674 .unwrap_or_else(|_| int_lit(0))
3675 } else {
3676 let id = ident_expr(escaped.as_str());
3677 method_call(id, "as_ptr", vec![])
3678 }
3679 } else {
3680 let b = self.build_syn_expr(base, info);
3681 method_call(b, "as_ptr", vec![])
3682 };
3683 let elem_str = self.infer_expr_type_unified(base, info)
3687 .and_then(|ut| ut.inner_type().cloned())
3688 .map(|inner| inner.to_rust_string());
3689 if let Some(elem) = elem_str {
3690 cast_syn_expr(raw_ptr_expr, &format!("*mut {}", elem))
3691 } else {
3692 raw_ptr_expr
3693 }
3694 } else {
3695 self.build_syn_expr(base, info)
3696 };
3697 let offset_call = method_call(base_expr, "offset", vec![i_isize]);
3698 deref(offset_call)
3699 }
3700 ExprKind::Conditional { cond, then_expr, else_expr } => {
3701 let c = self.build_syn_expr(cond, info);
3702 let c_str = expr_to_string(&c);
3703 let cond_str = self.wrap_as_bool_condition(cond, &c_str, info);
3704 let cond_syn: syn::Expr = syn::parse_str(&cond_str).unwrap_or(c);
3705
3706 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
3707 let tt = self.infer_expr_type_unified(then_expr, info);
3708 let et = self.infer_expr_type_unified(else_expr, info);
3709
3710 if let Some(ref hint) = type_hint {
3712 let hint_ut = UnifiedType::from_rust_str(hint);
3713 if hint_ut.is_pointer() {
3714 if is_null_literal(else_expr) {
3715 let t = self.build_syn_expr(then_expr, info);
3716 let e: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3717 .unwrap_or_else(|_| int_lit(0));
3718 return if_else(cond_syn, t, e);
3719 }
3720 if is_null_literal(then_expr) {
3721 let t: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3722 .unwrap_or_else(|_| int_lit(0));
3723 let e = self.build_syn_expr(else_expr, info);
3724 return if_else(cond_syn, t, e);
3725 }
3726 }
3727 if normalize_integer_type(hint).is_some() {
3730 if is_null_literal(else_expr) {
3731 let t = self.build_syn_expr(then_expr, info);
3732 return if_else(cond_syn, t, int_lit(0));
3733 }
3734 if is_null_literal(then_expr) {
3735 let e = self.build_syn_expr(else_expr, info);
3736 return if_else(cond_syn, int_lit(0), e);
3737 }
3738 }
3739 if hint_ut.is_bool() {
3740 let then_syn = match &then_expr.kind {
3741 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3742 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3743 _ => self.build_syn_expr(then_expr, info),
3744 };
3745 let else_syn = match &else_expr.kind {
3746 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3747 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3748 _ => self.build_syn_expr(else_expr, info),
3749 };
3750 return if_else(cond_syn, then_syn, else_syn);
3751 }
3752 }
3753
3754 let then_syn = if is_null_literal(then_expr) {
3756 if let Some(ref eut) = et {
3757 if eut.is_pointer() {
3758 syn::parse_str(&null_ptr_expr(eut)).unwrap_or_else(|_| int_lit(0))
3759 } else { self.build_syn_expr(then_expr, info) }
3760 } else { self.build_syn_expr(then_expr, info) }
3761 } else { self.build_syn_expr(then_expr, info) };
3762
3763 let else_syn = if is_null_literal(else_expr) {
3764 if let Some(ref tut) = tt {
3765 if tut.is_pointer() {
3766 syn::parse_str(&null_ptr_expr(tut)).unwrap_or_else(|_| int_lit(0))
3767 } else { self.build_syn_expr(else_expr, info) }
3768 } else { self.build_syn_expr(else_expr, info) }
3769 } else { self.build_syn_expr(else_expr, info) };
3770
3771 if let (Some(tut), Some(eut)) = (&tt, &et) {
3773 let ts = tut.to_rust_string();
3774 let es = eut.to_rust_string();
3775 if let (Some(tn), Some(en)) = (normalize_integer_type(&ts), normalize_integer_type(&es)) {
3776 if tn != en {
3777 if let Some(wider) = wider_integer_type(&ts, &es) {
3778 let (then_final, else_final) = if normalize_integer_type(&ts) != Some(wider) {
3779 (cast_syn_expr(then_syn, wider), else_syn)
3780 } else {
3781 (then_syn, cast_syn_expr(else_syn, wider))
3782 };
3783 return if_else(cond_syn, then_final, else_final);
3784 }
3785 }
3786 }
3787 if tut.is_pointer() && eut.is_pointer() && ts != es
3790 && is_sv_subtype_cast(tut, eut)
3791 {
3792 let target_str = type_hint.as_deref()
3795 .filter(|t| *t != "()" && !UnifiedType::from_rust_str(t).is_void())
3796 .unwrap_or(&ts)
3797 .to_string();
3798 return if_else(
3799 cond_syn,
3800 cast_syn_expr(then_syn, &target_str),
3801 cast_syn_expr(else_syn, &target_str),
3802 );
3803 }
3804 }
3805
3806 if_else(cond_syn, then_syn, else_syn)
3807 }
3808 ExprKind::Binary { op, lhs, rhs } => {
3809 if *op == BinOp::Sub {
3811 if let ExprKind::Sizeof(inner) = &lhs.kind {
3812 if let ExprKind::Ident(name) = &inner.kind {
3813 if self.current_literal_string_params.contains(name) {
3814 if let ExprKind::IntLit(1) = &rhs.kind {
3815 let param = escape_rust_keyword(self.interner.get(*name));
3816 return syn::parse_str(&format!("{}.len()", param))
3817 .unwrap_or_else(|_| int_lit(0));
3818 }
3819 }
3820 }
3821 }
3822 }
3823
3824 if matches!(op, BinOp::Eq | BinOp::Ne) {
3827 let s_eq = |s: &ExprKind| matches!(s, ExprKind::StringLit(_));
3828 let lhs_is_str = s_eq(&lhs.kind);
3829 let rhs_is_str = s_eq(&rhs.kind);
3830 if (lhs_is_str && is_null_literal(rhs))
3831 || (rhs_is_str && is_null_literal(lhs))
3832 {
3833 return syn::parse_str(
3834 if *op == BinOp::Eq { "false" } else { "true" }
3835 ).unwrap_or_else(|_| int_lit(0));
3836 }
3837 }
3838 if matches!(op, BinOp::Eq | BinOp::Ne) {
3842 let opt_lhs = (is_null_literal(rhs) || matches!(&rhs.kind, ExprKind::IntLit(0)))
3843 && self.is_option_fn_pointer_expr(lhs, info);
3844 let opt_rhs = (is_null_literal(lhs) || matches!(&lhs.kind, ExprKind::IntLit(0)))
3845 && self.is_option_fn_pointer_expr(rhs, info);
3846 if opt_lhs || opt_rhs {
3847 let receiver_expr = if opt_lhs { lhs } else { rhs };
3848 let r = self.build_syn_expr(receiver_expr, info);
3849 let method = if *op == BinOp::Eq { "is_none" } else { "is_some" };
3850 return syn::Expr::MethodCall(syn::ExprMethodCall {
3851 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3852 method: ident(method), turbofish: None,
3853 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3854 });
3855 }
3856 }
3857 if matches!(op, BinOp::Eq | BinOp::Ne) {
3859 if is_null_literal(rhs) {
3860 if self.is_pointer_expr_unified(lhs, info)
3861 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer()) {
3862 let l = self.build_syn_expr(lhs, info);
3863 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3864 attrs: vec![], receiver: Box::new(l), dot_token: Default::default(),
3865 method: ident("is_null"), turbofish: None,
3866 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3867 });
3868 return if *op == BinOp::Eq { is_null } else {
3869 syn::Expr::Unary(syn::ExprUnary {
3870 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3871 expr: Box::new(is_null),
3872 })
3873 };
3874 }
3875 }
3876 if is_null_literal(lhs) {
3877 if self.is_pointer_expr_unified(rhs, info)
3878 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer()) {
3879 let r = self.build_syn_expr(rhs, info);
3880 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3881 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3882 method: ident("is_null"), turbofish: None,
3883 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3884 });
3885 return if *op == BinOp::Eq { is_null } else {
3886 syn::Expr::Unary(syn::ExprUnary {
3887 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3888 expr: Box::new(is_null),
3889 })
3890 };
3891 }
3892 }
3893 if self.is_bool_expr_with_dict(lhs) {
3895 match (&rhs.kind, op) {
3896 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
3897 return self.build_syn_expr(lhs, info);
3898 }
3899 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
3900 let l = self.build_syn_expr(lhs, info);
3901 return syn::Expr::Unary(syn::ExprUnary {
3902 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3903 expr: Box::new(l),
3904 });
3905 }
3906 _ => {}
3907 }
3908 }
3909 if self.is_bool_expr_with_dict(rhs) {
3910 match (&lhs.kind, op) {
3911 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
3912 return self.build_syn_expr(rhs, info);
3913 }
3914 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
3915 let r = self.build_syn_expr(rhs, info);
3916 return syn::Expr::Unary(syn::ExprUnary {
3917 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3918 expr: Box::new(r),
3919 });
3920 }
3921 _ => {}
3922 }
3923 }
3924 }
3925
3926 if matches!(op, BinOp::Add | BinOp::Sub) {
3928 let l_arr = !self.is_static_array_expr(lhs)
3933 && self.is_array_like_expr(lhs, info);
3934 let r_arr = !self.is_static_array_expr(rhs)
3935 && self.is_array_like_expr(rhs, info);
3936 let lp = l_arr
3937 || self.is_static_array_expr(lhs)
3938 || self.is_pointer_expr_unified(lhs, info)
3939 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
3940 let rp = r_arr
3941 || self.is_static_array_expr(rhs)
3942 || self.is_pointer_expr_unified(rhs, info)
3943 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
3944 let l_is_static_arr = self.is_static_array_expr(lhs);
3951 let r_is_static_arr = self.is_static_array_expr(rhs);
3952 let cast_to_mut = |this: &mut Self, expr: syn::Expr, arr_expr: &Expr,
3953 needs_as_ptr: bool| -> syn::Expr {
3954 let elem = this.infer_expr_type_unified(arr_expr, info)
3955 .and_then(|ut| ut.inner_type().cloned())
3956 .map(|u| u.to_rust_string());
3957 let base = if needs_as_ptr {
3958 crate::syn_codegen::method_call(expr, "as_ptr", vec![])
3959 } else {
3960 expr
3961 };
3962 if let Some(e) = elem {
3963 crate::syn_codegen::cast_syn_expr(base, &format!("*mut {}", e))
3964 } else {
3965 base
3966 }
3967 };
3968 if lp && !rp {
3969 let l = self.build_syn_expr(lhs, info);
3970 let l = if l_arr {
3971 cast_to_mut(self, l, lhs, true)
3972 } else if l_is_static_arr {
3973 cast_to_mut(self, l, lhs, false)
3974 } else {
3975 l
3976 };
3977 let r = self.build_syn_expr(rhs, info);
3978 let r_isize = crate::syn_codegen::cast_syn_expr(r, "isize");
3979 let arg = if *op == BinOp::Add { r_isize } else {
3980 syn::Expr::Unary(syn::ExprUnary {
3981 attrs: vec![],
3982 op: syn::UnOp::Neg(Default::default()),
3983 expr: Box::new(r_isize),
3984 })
3985 };
3986 return crate::syn_codegen::method_call(l, "offset", vec![arg]);
3987 }
3988 if rp && !lp && *op == BinOp::Add {
3989 let l = self.build_syn_expr(lhs, info);
3990 let r = self.build_syn_expr(rhs, info);
3991 let r = if r_arr {
3992 cast_to_mut(self, r, rhs, true)
3993 } else if r_is_static_arr {
3994 cast_to_mut(self, r, rhs, false)
3995 } else {
3996 r
3997 };
3998 let l_isize = crate::syn_codegen::cast_syn_expr(l, "isize");
3999 return crate::syn_codegen::method_call(r, "offset", vec![l_isize]);
4000 }
4001 if lp && rp && *op == BinOp::Sub {
4002 let l = self.build_syn_expr(lhs, info);
4003 let r = self.build_syn_expr(rhs, info);
4004 return crate::syn_codegen::method_call(l, "offset_from", vec![r]);
4005 }
4006 }
4007
4008 if matches!(&rhs.kind, ExprKind::IntLit(_)) {
4010 if let Some(lut) = self.infer_expr_type_unified(lhs, info) {
4011 if lut.is_float() {
4012 if let ExprKind::IntLit(v) = &rhs.kind {
4013 let l = self.build_syn_expr(lhs, info);
4014 let l_str = expr_to_string(&l);
4015 return syn::parse_str(&format!("{} {} {}.0", l_str, bin_op_to_rust(*op), v))
4016 .unwrap_or_else(|_| int_lit(0));
4017 }
4018 }
4019 }
4020 }
4021 if matches!(&lhs.kind, ExprKind::IntLit(_)) {
4022 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4023 if rut.is_float() {
4024 if let ExprKind::IntLit(v) = &lhs.kind {
4025 let r = self.build_syn_expr(rhs, info);
4026 let r_str = expr_to_string(&r);
4027 return syn::parse_str(&format!("{}.0 {} {}", v, bin_op_to_rust(*op), r_str))
4028 .unwrap_or_else(|_| int_lit(0));
4029 }
4030 }
4031 }
4032 }
4033
4034 if matches!(op, BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Eq | BinOp::Ne) {
4039 if let (Some(lut), Some(rut)) =
4040 (self.infer_expr_type_unified(lhs, info),
4041 self.infer_expr_type_unified(rhs, info))
4042 {
4043 if lut.is_pointer() && rut.is_pointer()
4044 && pointer_inner_compatible(&lut, &rut)
4045 && (lut.is_const_pointer() != rut.is_const_pointer()
4046 || lut.to_rust_string() != rut.to_rust_string())
4047 {
4048 let l = self.build_syn_expr(lhs, info);
4049 let r = self.build_syn_expr(rhs, info);
4050 let target = lut.to_rust_string();
4051 return syn::Expr::Binary(syn::ExprBinary {
4052 attrs: vec![], left: Box::new(l),
4053 op: crate::syn_codegen::to_syn_binop(*op),
4054 right: Box::new(crate::syn_codegen::cast_syn_expr(r, &target)),
4055 });
4056 }
4057 }
4058 }
4059
4060 let l = self.build_syn_expr(lhs, info);
4061 let r = self.build_syn_expr(rhs, info);
4062
4063 if matches!(op, BinOp::LogAnd | BinOp::LogOr) {
4065 let l_str = expr_to_string(&l);
4066 let r_str = expr_to_string(&r);
4067 let l_bool = self.wrap_as_bool_condition(lhs, &l_str, info);
4068 let r_bool = self.wrap_as_bool_condition(rhs, &r_str, info);
4069 let l_syn: syn::Expr = syn::parse_str(&l_bool).unwrap_or(l);
4070 let r_syn: syn::Expr = syn::parse_str(&r_bool).unwrap_or(r);
4071 return syn::Expr::Binary(syn::ExprBinary {
4072 attrs: vec![], left: Box::new(l_syn),
4073 op: crate::syn_codegen::to_syn_binop(*op),
4074 right: Box::new(r_syn),
4075 });
4076 }
4077
4078 let lt = self.infer_expr_type_unified(lhs, info);
4080 let rt = self.infer_expr_type_unified(rhs, info);
4081
4082 let make_binary_op = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4086 syn::Expr::Binary(syn::ExprBinary {
4087 attrs: vec![], left: Box::new(left),
4088 op: crate::syn_codegen::to_syn_binop(*op),
4089 right: Box::new(right),
4090 })
4091 };
4092 match (<, &rt) {
4093 (Some(lut), None) if self.is_rust_enum_type(lut) => {
4094 return make_binary_op(cast_syn_expr(l, "u32"), r);
4095 }
4096 (None, Some(rut)) if self.is_rust_enum_type(rut) => {
4097 return make_binary_op(l, cast_syn_expr(r, "u32"));
4098 }
4099 _ => {}
4100 }
4101
4102 if let (Some(lut), Some(rut)) = (<, &rt) {
4103 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4104 syn::Expr::Binary(syn::ExprBinary {
4105 attrs: vec![], left: Box::new(left),
4106 op: crate::syn_codegen::to_syn_binop(*op),
4107 right: Box::new(right),
4108 })
4109 };
4110 let l_is_enum = self.is_rust_enum_type(lut);
4113 let r_is_enum = self.is_rust_enum_type(rut);
4114 if l_is_enum && !r_is_enum {
4115 let rs = rut.to_rust_string();
4116 let target = normalize_integer_type(&rs).unwrap_or("u32");
4117 return make_binary(cast_syn_expr(l, target), r);
4118 }
4119 if r_is_enum && !l_is_enum {
4120 let ls = lut.to_rust_string();
4121 let target = normalize_integer_type(&ls).unwrap_or("u32");
4122 return make_binary(l, cast_syn_expr(r, target));
4123 }
4124 if rut.is_bool() {
4126 let ls = lut.to_rust_string();
4127 if let Some(nl) = normalize_integer_type(&ls) {
4128 return make_binary(l, cast_syn_expr(r, nl));
4129 }
4130 }
4131 if lut.is_bool() {
4132 let rs = rut.to_rust_string();
4133 if let Some(nr) = normalize_integer_type(&rs) {
4134 return make_binary(cast_syn_expr(l, nr), r);
4135 }
4136 }
4137 if lut.is_float() && !rut.is_float() {
4139 let ls = lut.to_rust_string();
4140 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4141 return make_binary(l, cast_syn_expr(r, float_ty));
4142 }
4143 if rut.is_float() && !lut.is_float() {
4144 let rs = rut.to_rust_string();
4145 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4146 return make_binary(cast_syn_expr(l, float_ty), r);
4147 }
4148 let ls = lut.to_rust_string();
4150 let rs = rut.to_rust_string();
4151 if let Some(wider) = wider_integer_type(&ls, &rs) {
4152 if normalize_integer_type(&ls) != Some(wider) {
4153 return make_binary(cast_syn_expr(l, wider), r);
4154 } else {
4155 return make_binary(l, cast_syn_expr(r, wider));
4156 }
4157 }
4158 }
4159 {
4161 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4162 syn::Expr::Binary(syn::ExprBinary {
4163 attrs: vec![], left: Box::new(left),
4164 op: crate::syn_codegen::to_syn_binop(*op),
4165 right: Box::new(right),
4166 })
4167 };
4168 match (<, &rt) {
4169 (Some(lut), None) if lut.is_float() => {
4170 let ls = lut.to_rust_string();
4171 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4172 return make_binary(l, cast_syn_expr(r, float_ty));
4173 }
4174 (None, Some(rut)) if rut.is_float() => {
4175 let rs = rut.to_rust_string();
4176 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4177 return make_binary(cast_syn_expr(l, float_ty), r);
4178 }
4179 _ => {}
4180 }
4181 if matches!(op, BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor) {
4183 match (<, &rt) {
4184 (Some(lut), None) => {
4185 let ls = lut.to_rust_string();
4186 if let Some(nl) = normalize_integer_type(&ls) {
4187 return make_binary(l, cast_syn_expr(r, nl));
4188 }
4189 }
4190 (None, Some(rut)) => {
4191 let rs = rut.to_rust_string();
4192 if let Some(nr) = normalize_integer_type(&rs) {
4193 return make_binary(cast_syn_expr(l, nr), r);
4194 }
4195 }
4196 _ => {}
4197 }
4198 }
4199 }
4200 syn::Expr::Binary(syn::ExprBinary {
4202 attrs: vec![],
4203 left: Box::new(l),
4204 op: crate::syn_codegen::to_syn_binop(*op),
4205 right: Box::new(r),
4206 })
4207 }
4208 ExprKind::Call { func, args } => {
4209 if let Some(syn_call) = self.try_build_common_macro_fn_call(func, args, info) {
4213 return syn_call;
4214 }
4215 if let ExprKind::Ident(name) = &func.kind {
4217 let func_name = self.interner.get(*name);
4218 if func_name == "__builtin_expect" && !args.is_empty() {
4220 return self.build_syn_expr(&args[0], info);
4221 }
4222 if func_name == "__builtin_unreachable" {
4224 return syn::parse_str("std::hint::unreachable_unchecked()").unwrap();
4225 }
4226 if (func_name == "__builtin_ctz" || func_name == "__builtin_ctzl") && args.len() == 1 {
4228 let arg = self.build_syn_expr(&args[0], info);
4229 return syn::Expr::MethodCall(syn::ExprMethodCall {
4230 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4231 method: ident("trailing_zeros"), turbofish: None,
4232 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4233 });
4234 }
4235 if (func_name == "__builtin_clz" || func_name == "__builtin_clzl") && args.len() == 1 {
4236 let arg = self.build_syn_expr(&args[0], info);
4237 return syn::Expr::MethodCall(syn::ExprMethodCall {
4238 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4239 method: ident("leading_zeros"), turbofish: None,
4240 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4241 });
4242 }
4243 if matches!(func_name, "ASSERT_IS_LITERAL" | "ASSERT_IS_PTR" | "ASSERT_NOT_PTR")
4245 && args.len() == 1
4246 {
4247 return self.build_syn_expr(&args[0], info);
4248 }
4249 if matches!(func_name, "offsetof" | "__builtin_offsetof") && args.len() == 2 {
4258 let type_name_str = if let ExprKind::Ident(name) = &args[0].kind {
4259 escape_rust_keyword(self.interner.get(*name)).to_string()
4260 } else {
4261 let s = self.build_syn_expr(&args[0], info);
4262 expr_to_string(&s)
4263 };
4264 if let Some(field_path) = self.expr_to_field_path(&args[1]) {
4265 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_name_str, field_path))
4266 .unwrap_or_else(|_| int_lit(0));
4267 }
4268 }
4269 }
4270
4271 let f_syn = self.build_syn_expr(func, info);
4273 let f_str = expr_to_string(&f_syn);
4274
4275 let callee_name = if let ExprKind::Ident(name) = &func.kind { Some(*name) } else { None };
4276 let needs_my_perl = callee_name
4277 .map(|name| self.needs_my_perl_for_call(name, args.len()))
4278 .unwrap_or(false);
4279
4280 let callee_generics = callee_name
4282 .and_then(|name| self.get_callee_generic_params(name).cloned());
4283
4284 if let Some(ref generics) = callee_generics {
4285 let mut type_args = Vec::new();
4287 let mut value_args: Vec<String> = if needs_my_perl {
4288 vec!["my_perl".to_string()]
4289 } else { vec![] };
4290 let mut value_idx = if needs_my_perl { 1usize } else { 0 };
4291 for (i, arg) in args.iter().enumerate() {
4292 if generics.contains_key(&(i as i32)) {
4293 let syn_arg = self.build_syn_expr(arg, info);
4294 type_args.push(normalize_parens(&expr_to_string(&syn_arg)));
4295 } else {
4296 value_args.push(self.build_arg_string_unified(arg, info, callee_name, value_idx));
4297 value_idx += 1;
4298 }
4299 }
4300 return syn::parse_str(&format!("{}::<{}>({})", f_str, type_args.join(", "), value_args.join(", ")))
4301 .unwrap_or_else(|_| int_lit(0));
4302 }
4303
4304 let mut arg_strs: Vec<String> = if needs_my_perl {
4306 vec!["my_perl".to_string()]
4307 } else { vec![] };
4308 let arg_offset = if needs_my_perl { 1usize } else { 0 };
4309 for (i, arg) in args.iter().enumerate() {
4310 arg_strs.push(self.build_arg_string_unified(arg, info, callee_name, i + arg_offset));
4311 }
4312 syn::parse_str(&format!("{}({})", f_str, arg_strs.join(", ")))
4313 .unwrap_or_else(|_| int_lit(0))
4314 }
4315 ExprKind::MacroCall { name, args, expanded, .. } => {
4316 if self.should_emit_as_macro_call(*name) {
4317 let name_str = escape_rust_keyword(self.interner.get(*name));
4318 let needs_my_perl = self.needs_my_perl_for_call(*name, args.len());
4319 let mut a: Vec<String> = if needs_my_perl {
4320 vec!["my_perl".to_string()]
4321 } else { vec![] };
4322 for arg in args {
4323 let arg_str = expr_to_string(&self.build_syn_expr(arg, info));
4324 a.push(normalize_parens(&arg_str));
4325 }
4326 syn::parse_str(&format!("{}({})", name_str, a.join(", ")))
4327 .unwrap_or_else(|_| int_lit(0))
4328 } else {
4329 self.build_syn_expr(expanded, info)
4330 }
4331 }
4332 ExprKind::BuiltinCall { name, args } => {
4333 let func_name = self.interner.get(*name);
4334 if matches!(func_name, "offsetof" | "__builtin_offsetof" | "STRUCT_OFFSET")
4335 && args.len() == 2
4336 {
4337 let type_str = match &args[0] {
4338 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4339 crate::ast::BuiltinArg::Expr(e) => {
4340 let s = self.build_syn_expr(e, info);
4341 expr_to_string(&s)
4342 }
4343 };
4344 let field_expr = match &args[1] {
4345 crate::ast::BuiltinArg::Expr(e) => self.expr_to_field_path(e),
4346 _ => None,
4347 };
4348 if let Some(fp) = field_expr {
4349 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_str, fp))
4350 .unwrap_or_else(|_| int_lit(0));
4351 }
4352 }
4353 let a: Vec<String> = args.iter().map(|arg| match arg {
4355 crate::ast::BuiltinArg::Expr(e) => {
4356 let s = self.build_syn_expr(e, info);
4357 expr_to_string(&s)
4358 }
4359 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4360 }).collect();
4361 syn::parse_str(&format!("{}({})", func_name, a.join(", ")))
4362 .unwrap_or_else(|_| int_lit(0))
4363 }
4364 ExprKind::Assign { op, lhs, rhs } => {
4365 self.build_assign_syn_expr(*op, lhs, rhs, info)
4366 }
4367 ExprKind::PreInc(inner) => {
4368 self.build_inc_dec_syn_expr(inner, info, true, false)
4369 }
4370 ExprKind::PreDec(inner) => {
4371 self.build_inc_dec_syn_expr(inner, info, false, false)
4372 }
4373 ExprKind::PostInc(inner) => {
4374 self.build_inc_dec_syn_expr(inner, info, true, true)
4375 }
4376 ExprKind::PostDec(inner) => {
4377 self.build_inc_dec_syn_expr(inner, info, false, true)
4378 }
4379 ExprKind::Assert { kind, condition } => {
4380 let assert_str = if let Some((real_cond, msg)) = decompose_assert_with_message(condition) {
4381 let c = self.build_syn_expr(real_cond, info);
4382 let c_str = expr_to_string(&c);
4383 let cond_str = self.wrap_as_bool_condition(real_cond, &c_str, info);
4384 format!("assert!({}, \"{}\")", normalize_parens(&cond_str), msg)
4385 } else {
4386 let c = self.build_syn_expr(condition, info);
4387 let c_str = expr_to_string(&c);
4388 if is_boolean_expr(condition) || self.is_bool_expr_with_dict(condition) {
4389 format!("assert!({})", normalize_parens(&c_str))
4390 } else if self.is_pointer_expr_unified(condition, info)
4391 || self.infer_expr_type_unified(condition, info).is_some_and(|ut| ut.is_pointer()) {
4392 format!("assert!(!({}).is_null())", c_str)
4396 } else {
4397 format!("assert!({} != 0)", normalize_parens(&c_str))
4398 }
4399 };
4400 let result = match kind {
4401 AssertKind::Assert => assert_str,
4402 AssertKind::AssertUnderscore => format!("{{ {}; }}", assert_str),
4403 };
4404 syn::parse_str(&result).unwrap_or_else(|_| int_lit(0))
4405 }
4406 ExprKind::StmtExpr(compound) => {
4407 if let Some(init_expr) = self.detect_mutable_ptr_pattern(compound) {
4409 return self.build_syn_expr(init_expr, info);
4410 }
4411 let mut parts: Vec<String> = Vec::new();
4415 for item in &compound.items {
4416 match item {
4417 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => {
4418 parts.push(self.build_expr_string(e, info));
4419 }
4420 BlockItem::Stmt(stmt) => {
4421 let s = match info {
4422 Some(info) => self.stmt_to_rust(stmt, info),
4423 None => self.stmt_to_rust_inline(stmt, ""),
4424 };
4425 parts.push(s);
4426 }
4427 BlockItem::Decl(decl) => {
4428 self.collect_decl_types(decl);
4429 let decl_str = self.decl_to_rust_let(decl, "");
4430 for line in decl_str.lines() {
4431 let trimmed = line.trim();
4432 if !trimmed.is_empty() {
4433 parts.push(trimmed.strip_suffix(';').unwrap_or(trimmed).to_string());
4434 }
4435 }
4436 }
4437 }
4438 }
4439 let block_str = if parts.is_empty() {
4440 "{ }".to_string()
4441 } else if parts.len() == 1 {
4442 parts.pop().unwrap()
4443 } else {
4444 let last = parts.pop().unwrap();
4445 let stmts = parts.join("; ");
4446 format!("{{ {}; {} }}", stmts, last)
4447 };
4448 syn::parse_str(&block_str).unwrap_or_else(|_| int_lit(0))
4449 }
4450 ExprKind::Alignof(ty) => {
4451 let ty_str = self.type_name_to_rust(ty);
4452 syn::parse_str(&format!("std::mem::align_of::<{}>()", ty_str))
4453 .unwrap_or_else(|_| int_lit(0))
4454 }
4455 _ => {
4459 self.codegen_errors.push(format!(
4460 "unhandled ExprKind in syn codegen: {:?}",
4461 std::mem::discriminant(&expr.kind)
4462 ));
4463 int_lit(0)
4464 }
4465 }
4466 }
4467
4468 fn build_arg_string_unified(&mut self, arg: &Expr, info: Option<&MacroInferInfo>,
4472 callee: Option<InternedStr>, arg_index: usize) -> String {
4473 if info.is_some() {
4475 if let Some(name) = self.find_literal_string_ident(arg) {
4476 if let Some(callee_name) = callee {
4477 if self.callee_expects_literal_string(callee_name, arg_index) {
4478 return escape_rust_keyword(self.interner.get(*name));
4479 }
4480 }
4481 let param = escape_rust_keyword(self.interner.get(*name));
4482 return format!("{}.as_ptr() as *const c_char", param);
4483 }
4484 }
4485 if is_null_literal(arg) {
4487 if let Some(callee_name) = callee {
4488 let func_name = self.interner.get(callee_name).to_string();
4489 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4490 if expected_ut.is_pointer() {
4491 return null_ptr_expr(&expected_ut);
4492 }
4493 }
4494 }
4495 }
4496 if let Some(callee_name) = callee {
4498 let func_name = self.interner.get(callee_name);
4499 if self.callee_param_is_bool(func_name, arg_index) {
4500 match &arg.kind {
4501 ExprKind::IntLit(0) => return "false".to_string(),
4502 ExprKind::IntLit(1) => return "true".to_string(),
4503 _ => {}
4504 }
4505 }
4506 }
4507 let mut syn_expr = self.build_syn_expr(arg, info);
4509 if let Some(callee_name) = callee {
4512 let func_name = self.interner.get(callee_name).to_string();
4513 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4514 let actual_ut = self.infer_expr_type_unified(arg, info);
4515 let actual_ty = actual_ut.as_ref().map(|ut| ut.to_rust_string());
4516 let expected_ty = expected_ut.to_rust_string();
4517 if matches!(&arg.kind, ExprKind::StringLit(_))
4521 && expected_ut.is_pointer()
4522 {
4523 syn_expr = crate::syn_codegen::method_call(syn_expr, "as_ptr", vec![]);
4524 }
4525 syn_expr = self.cast_arg_syn_if_needed(syn_expr, actual_ty.as_deref(), &expected_ty);
4526 }
4527 }
4528 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
4529 }
4530
4531 fn cast_arg_syn_if_needed(&self, arg_expr: syn::Expr,
4535 actual_ty: Option<&str>, expected_ty: &str) -> syn::Expr {
4536 use crate::syn_codegen::cast_syn_expr;
4537 if let Some(actual) = actual_ty {
4538 let actual_ut = UnifiedType::from_rust_str(actual);
4540 if self.is_rust_enum_type(&actual_ut) {
4541 if let Some(target) = normalize_integer_type(expected_ty) {
4542 return cast_syn_expr(arg_expr, target);
4543 }
4544 }
4545 let na = normalize_integer_type(actual);
4546 let ne = normalize_integer_type(expected_ty);
4547 if let (Some(a), Some(e)) = (na, ne) {
4548 if !integer_types_compatible(a, e) {
4549 return cast_syn_expr(arg_expr, e);
4550 }
4551 return arg_expr;
4552 }
4553 if actual != expected_ty {
4555 let actual_ut = UnifiedType::from_rust_str(actual);
4556 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4557 if actual_ut.is_pointer() && expected_ut.is_pointer()
4558 && is_sv_subtype_cast(&actual_ut, &expected_ut) {
4559 let cast_ty = if actual.contains("*const") {
4560 expected_ty.replace("*mut", "*const")
4561 } else {
4562 expected_ty.to_string()
4563 };
4564 return cast_syn_expr(arg_expr, &cast_ty);
4565 }
4566 if actual_ut.is_pointer() && expected_ut.is_pointer()
4572 && expected_ut.is_void_pointer()
4573 {
4574 return cast_syn_expr(arg_expr, expected_ty);
4575 }
4576 if pointer_inner_compatible(&actual_ut, &expected_ut) {
4582 let top_mut_to_const = !actual_ut.is_const_pointer()
4583 && expected_ut.is_const_pointer();
4584 let top_const_same = actual_ut.is_const_pointer()
4585 == expected_ut.is_const_pointer();
4586 let inner_exact_match = actual_ut.inner_type()
4588 .zip(expected_ut.inner_type())
4589 .is_some_and(|(a, b)| a.to_rust_string() == b.to_rust_string());
4590 let auto_coerces = (top_mut_to_const || top_const_same)
4591 && inner_exact_match;
4592 if !auto_coerces {
4593 return cast_syn_expr(arg_expr, expected_ty);
4594 }
4595 }
4596 }
4597 return arg_expr;
4598 }
4599 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4601 if expected_ut.is_pointer() {
4602 if let Some(inner) = expected_ut.inner_type() {
4603 if let UnifiedType::Named(name) = inner {
4604 let n = name.as_str();
4605 if matches!(n, "SV" | "GV" | "HV" | "AV" | "CV" | "IO") {
4606 if matches!(&arg_expr, syn::Expr::Call(_) | syn::Expr::MethodCall(_)) {
4607 return cast_syn_expr(arg_expr, expected_ty);
4608 }
4609 }
4610 }
4611 }
4612 }
4613 arg_expr
4614 }
4615
4616 fn try_build_common_macro_fn_call(
4632 &mut self,
4633 func: &Expr,
4634 args: &[Expr],
4635 info: Option<&MacroInferInfo>,
4636 ) -> Option<syn::Expr> {
4637 use crate::syn_codegen::*;
4638
4639 let member_id = match &func.kind {
4640 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => *member,
4641 _ => return None,
4642 };
4643
4644 let mut is_fn_ptr = self
4646 .fields_dict
4647 .and_then(|d| d.canonical_field(member_id).map(|(_, f)| f.is_fn_pointer))
4648 .unwrap_or(false);
4649
4650 if !is_fn_ptr {
4655 let field_name = self.interner.get(member_id);
4656 if let Some(ut) = self.field_type_map.get(field_name) {
4657 let ty_str = ut.to_rust_string();
4658 if type_str_is_fn_pointer(&ty_str) {
4659 is_fn_ptr = true;
4660 } else if let Some(dict) = self.rust_decl_dict {
4661 if let Some(alias) = dict.types.get(&ty_str) {
4662 if type_str_is_fn_pointer(&alias.ty) {
4663 is_fn_ptr = true;
4664 }
4665 }
4666 }
4667 }
4668 }
4669
4670 if !is_fn_ptr {
4671 return None;
4672 }
4673
4674 let field_access = self.build_syn_expr(func, info);
4676 let callee = method_call(field_access, "unwrap_unchecked", vec![]);
4678
4679 let mut punctuated = syn::punctuated::Punctuated::new();
4681 for (i, arg) in args.iter().enumerate() {
4682 let s = self.build_arg_string_unified(arg, info, None, i);
4683 let parsed = syn::parse_str(&s).unwrap_or_else(|_| int_lit(0));
4684 punctuated.push(parsed);
4685 }
4686
4687 Some(syn::Expr::Call(syn::ExprCall {
4688 attrs: vec![],
4689 func: Box::new(callee),
4690 paren_token: Default::default(),
4691 args: punctuated,
4692 }))
4693 }
4694
4695 fn build_lvalue_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
4697 if let ExprKind::MacroCall { expanded, .. } = &expr.kind {
4698 return self.build_syn_expr(expanded, info);
4699 }
4700 if let ExprKind::Call { func, args } = &expr.kind {
4701 if let Some(expanded) = self.try_expand_call_as_lvalue_syn(func, args, info) {
4702 return expanded;
4703 }
4704 let syn_expr = self.build_syn_expr(expr, info);
4705 let s = crate::syn_codegen::expr_to_string(&syn_expr);
4706 self.codegen_errors.push(format!("invalid lvalue: {} cannot be assigned to", s));
4707 return syn_expr;
4708 }
4709 self.build_syn_expr(expr, info)
4710 }
4711
4712 fn build_inc_dec_syn_expr(&mut self, inner: &Expr, info: Option<&MacroInferInfo>,
4715 is_inc: bool, is_post: bool) -> syn::Expr {
4716 use crate::syn_codegen::*;
4717 let lv = self.build_lvalue_syn_expr(inner, info);
4718 let is_ptr = self.is_pointer_expr_unified(inner, info)
4719 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer());
4720 let step_stmt: syn::Stmt = if is_ptr {
4722 let method = if is_inc { "wrapping_add" } else { "wrapping_sub" };
4724 let call = method_call(lv.clone(), method, vec![int_lit(1)]);
4725 semi_stmt(assign_expr(lv.clone(), call))
4726 } else {
4727 let op = if is_inc {
4728 syn::BinOp::AddAssign(Default::default())
4729 } else {
4730 syn::BinOp::SubAssign(Default::default())
4731 };
4732 semi_stmt(assign_op_expr(lv.clone(), op, int_lit(1)))
4733 };
4734 if is_post {
4735 let save = let_stmt("_t", lv.clone());
4737 block_with_value(vec![save, step_stmt], ident_expr("_t"))
4738 } else {
4739 block_with_value(vec![step_stmt], lv)
4741 }
4742 }
4743
4744 fn build_assign_syn_expr(&mut self, op: AssignOp, lhs: &Expr, rhs: &Expr,
4747 info: Option<&MacroInferInfo>) -> syn::Expr {
4748 use crate::syn_codegen::*;
4749 let l = self.build_lvalue_syn_expr(lhs, info);
4750 let lhs_ut = self.infer_expr_type_unified(lhs, info);
4751
4752 let r: syn::Expr = if is_null_literal(rhs) && op == AssignOp::Assign {
4754 match &lhs_ut {
4755 Some(lut) if lut.is_pointer() => {
4756 if lut.is_const_pointer() {
4757 syn::parse_str("std::ptr::null()").unwrap_or_else(|_| int_lit(0))
4758 } else {
4759 syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0))
4760 }
4761 }
4762 Some(_) => int_lit(0),
4763 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
4764 }
4765 } else {
4766 let mut r_expr = self.build_syn_expr(rhs, info);
4767 if op == AssignOp::Assign {
4769 if let Some(ref lut) = lhs_ut {
4771 if lut.is_float() {
4772 if let ExprKind::IntLit(n) = &rhs.kind {
4773 r_expr = syn::parse_str(&format!("{}.0", n))
4774 .unwrap_or_else(|_| int_lit(0));
4775 }
4776 }
4777 }
4778 if let Some(ref lut) = lhs_ut {
4779 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4780 let ls = lut.to_rust_string();
4781 let rs = rut.to_rust_string();
4782 if let (Some(nl), Some(nr)) = (
4783 normalize_integer_type(&ls),
4784 normalize_integer_type(&rs),
4785 ) {
4786 if !integer_types_compatible(nl, nr) {
4787 r_expr = cast_syn_expr(r_expr, nl);
4788 }
4789 }
4790 else if lut.is_pointer() && rut.is_pointer()
4792 && lut.is_const_pointer() != rut.is_const_pointer()
4793 {
4794 r_expr = cast_syn_expr(r_expr, &ls);
4795 }
4796 else if lut.is_pointer() && rut.is_pointer()
4798 && ls != rs
4799 && is_sv_subtype_cast(&rut, lut)
4800 {
4801 r_expr = cast_syn_expr(r_expr, &ls);
4802 }
4803 }
4804 }
4805 }
4806 r_expr
4807 };
4808
4809 if op == AssignOp::Assign {
4813 if let syn::Expr::MethodCall(mc) = &l {
4814 if mc.args.is_empty() {
4815 let method_name = mc.method.to_string();
4816 if self.is_bitfield_method(&method_name) {
4817 let setter_name = format!("set_{}", method_name);
4818 let arg_val = if let Some(dict) = self.rust_decl_dict {
4822 let ret_ty = dict.bitfield_method_types.iter()
4825 .find(|((_, m), _)| m == &method_name)
4826 .map(|(_, ty)| ty.clone());
4827 if let Some(ty) = ret_ty {
4828 cast_syn_expr(r, &ty)
4829 } else {
4830 r
4831 }
4832 } else {
4833 r
4834 };
4835 let setter_call = method_call(
4836 (*mc.receiver).clone(),
4837 &setter_name,
4838 vec![arg_val],
4839 );
4840 let stmt = semi_stmt(setter_call);
4841 return block_with_value(vec![stmt], l);
4842 }
4843 }
4844 }
4845 }
4846
4847 let stmt: syn::Stmt = match op {
4849 AssignOp::Assign => semi_stmt(assign_expr(l.clone(), r)),
4850 AssignOp::AddAssign | AssignOp::SubAssign => {
4851 let is_ptr = self.is_pointer_expr_unified(lhs, info)
4852 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer());
4853 if is_ptr {
4854 let method = if op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
4856 let r_usize = cast_syn_expr(r, "usize");
4857 let call = method_call(l.clone(), method, vec![r_usize]);
4858 semi_stmt(assign_expr(l.clone(), call))
4859 } else {
4860 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4861 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
4862 }
4863 }
4864 AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign => {
4865 let lt = &lhs_ut;
4869 let rt = self.infer_expr_type_unified(rhs, info);
4870 let r_final = {
4871 let mut casted = false;
4872 let mut ret = r;
4873 if let (Some(lut), Some(rut)) = (lt, &rt) {
4874 let ls = lut.to_rust_string();
4875 let rs = rut.to_rust_string();
4876 let nl = normalize_integer_type(&ls);
4877 let nr = normalize_integer_type(&rs);
4878 if nl.is_some() && nr.is_some() && nl != nr {
4879 ret = cast_syn_expr(ret, nl.unwrap());
4880 casted = true;
4881 }
4882 if !casted && self.is_rust_enum_type(rut) && nl.is_some() {
4884 ret = cast_syn_expr(ret, nl.unwrap());
4885 casted = true;
4886 }
4887 }
4888 if !casted {
4889 if let (Some(lut), None) = (lt, &rt) {
4890 let ls = lut.to_rust_string();
4891 if let Some(nl) = normalize_integer_type(&ls) {
4892 ret = cast_syn_expr(ret, nl);
4893 }
4894 }
4895 }
4896 ret
4897 };
4898 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4899 semi_stmt(assign_op_expr(l.clone(), syn_op, r_final))
4900 }
4901 _ => {
4902 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4903 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
4904 }
4905 };
4906 block_with_value(vec![stmt], l)
4907 }
4908
4909 fn build_lvalue_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
4911 let syn_expr = self.build_lvalue_syn_expr(expr, info);
4912 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
4913 }
4914
4915 fn build_syn_expr_with_type_hint(&mut self, expr: &Expr, info: Option<&MacroInferInfo>,
4917 type_hint: Option<&str>) -> syn::Expr {
4918 use crate::syn_codegen::*;
4919 if let Some(ty) = type_hint {
4920 let ut = UnifiedType::from_rust_str(ty);
4921 if ut.is_pointer() && is_null_literal(expr) {
4922 return syn::parse_str(&null_ptr_expr(&ut)).unwrap_or_else(|_| int_lit(0));
4923 }
4924 if ut.is_bool() {
4925 match &expr.kind {
4926 ExprKind::IntLit(0) => return syn::parse_str("false").unwrap(),
4927 ExprKind::IntLit(1) => return syn::parse_str("true").unwrap(),
4928 _ => {}
4929 }
4930 }
4931 }
4932 self.build_syn_expr(expr, info)
4933 }
4934
4935 fn build_return_stmt(&mut self, expr: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
4945 use crate::syn_codegen::*;
4946 if let Some(ref rt) = self.current_return_type {
4947 if rt.is_pointer() && is_null_literal(expr) {
4948 return format!("{}return {};", indent, null_ptr_expr(rt));
4949 }
4950 if rt.is_bool() {
4951 match &expr.kind {
4952 ExprKind::IntLit(0) => return format!("{}return false;", indent),
4953 ExprKind::IntLit(1) => return format!("{}return true;", indent),
4954 _ => {
4955 let mut syn_expr = self.build_syn_expr(expr, info);
4956 if !self.is_bool_expr_with_dict(expr) && !is_bool_syn_expr(&syn_expr) {
4957 syn_expr = wrap_as_bool(syn_expr);
4958 }
4959 let s = normalize_parens(&expr_to_string(&syn_expr));
4960 return format!("{}return {};", indent, s);
4961 }
4962 }
4963 }
4964 }
4965 let mut syn_expr = self.build_syn_expr(expr, info);
4966 syn_expr = self.cast_return_syn_expr_if_needed(expr, info, syn_expr);
4967 let s = normalize_parens(&expr_to_string(&syn_expr));
4968 format!("{}return {};", indent, s)
4969 }
4970
4971 fn cast_return_syn_expr_if_needed(&self, expr: &Expr, info: Option<&MacroInferInfo>,
4974 syn_expr: syn::Expr) -> syn::Expr {
4975 let Some(ret_ut) = &self.current_return_type else { return syn_expr };
4976 let Some(expr_ut) = self.infer_expr_type_unified(expr, info) else { return syn_expr };
4977 let ret_s = ret_ut.to_rust_string();
4978 let expr_s = expr_ut.to_rust_string();
4979 if self.is_rust_enum_type(&expr_ut) {
4981 if let Some(nr) = normalize_integer_type(&ret_s) {
4982 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
4983 }
4984 }
4985 if let (Some(nr), Some(ne)) = (normalize_integer_type(&ret_s), normalize_integer_type(&expr_s)) {
4986 if !integer_types_compatible(nr, ne) {
4987 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
4988 }
4989 }
4990 if ret_ut.is_pointer() && expr_ut.is_pointer() && ret_s != expr_s
4994 && pointer_inner_compatible(ret_ut, &expr_ut)
4995 {
4996 return crate::syn_codegen::cast_syn_expr(syn_expr, &ret_s);
4997 }
4998 syn_expr
4999 }
5000
5001 fn build_assign_stmt(&mut self, op: &AssignOp, lhs: &Expr, rhs: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
5007 use crate::syn_codegen::*;
5008 let l = self.build_lvalue_string(lhs, info);
5009 let lhs_ut = self.infer_expr_type_unified(lhs, info);
5010
5011 let r_syn: syn::Expr = if is_null_literal(rhs) && *op == AssignOp::Assign {
5013 match &lhs_ut {
5014 Some(lut) if lut.is_pointer() => {
5015 let s = if lut.is_const_pointer() { "std::ptr::null()" } else { "std::ptr::null_mut()" };
5016 syn::parse_str(s).unwrap_or_else(|_| int_lit(0))
5017 }
5018 Some(_) => int_lit(0),
5019 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
5020 }
5021 } else {
5022 let mut r_syn = self.build_syn_expr(rhs, info);
5023 if *op == AssignOp::Assign {
5025 if let Some(ref lut) = lhs_ut {
5027 if lut.is_float() {
5028 if let ExprKind::IntLit(n) = &rhs.kind {
5029 r_syn = syn::parse_str(&format!("{}.0", n))
5030 .unwrap_or_else(|_| int_lit(0));
5031 }
5032 }
5033 }
5034 if let Some(ref lut) = lhs_ut {
5035 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
5036 let ls = lut.to_rust_string();
5037 let rs = rut.to_rust_string();
5038 if self.is_rust_enum_type(&rut) {
5040 if let Some(nl) = normalize_integer_type(&ls) {
5041 r_syn = cast_syn_expr(r_syn, nl);
5042 }
5043 } else if let (Some(nl), Some(nr)) = (normalize_integer_type(&ls), normalize_integer_type(&rs)) {
5044 if nl != nr {
5047 r_syn = cast_syn_expr(r_syn, nl);
5048 }
5049 }
5050 if pointer_const_differs(lut, &rut) {
5053 r_syn = cast_syn_expr(r_syn, &ls);
5054 } else if lut.is_pointer() && rut.is_pointer()
5055 && ls != rs
5056 && pointer_inner_compatible(lut, &rut)
5057 {
5058 r_syn = cast_syn_expr(r_syn, &ls);
5059 }
5060 else if lut.is_pointer() && rut.is_pointer()
5063 && ls != rs
5064 && is_sv_subtype_cast(&rut, lut)
5065 {
5066 r_syn = cast_syn_expr(r_syn, &ls);
5067 }
5068 }
5069 }
5070 } else if matches!(op, AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign) {
5071 let rt = self.infer_expr_type_unified(rhs, info);
5072 if let (Some(lut), Some(rut)) = (&lhs_ut, &rt) {
5073 let ls = lut.to_rust_string();
5074 let rs = rut.to_rust_string();
5075 let nl = normalize_integer_type(&ls);
5076 let nr = normalize_integer_type(&rs);
5077 if nl.is_some() && nr.is_some() && nl != nr {
5078 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5079 } else if self.is_rust_enum_type(rut) && nl.is_some() {
5080 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5082 }
5083 } else if let (Some(lut), None) = (&lhs_ut, &rt) {
5084 let ls = lut.to_rust_string();
5085 if let Some(nl) = normalize_integer_type(&ls) {
5086 r_syn = cast_syn_expr(r_syn, nl);
5087 }
5088 }
5089 }
5090 r_syn
5091 };
5092
5093 match op {
5094 AssignOp::Assign => {
5095 let r = normalize_parens(&expr_to_string(&r_syn));
5096 format!("{}{} = {};", indent, l, r)
5097 }
5098 AssignOp::AddAssign | AssignOp::SubAssign => {
5099 if self.is_pointer_expr_unified(lhs, info)
5100 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer()) {
5101 let method = if *op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
5102 let r_usize = cast_syn_expr(r_syn, "usize");
5103 let r = expr_to_string(&r_usize);
5104 format!("{}{} = {}.{}({});", indent, l, l, method, r)
5105 } else {
5106 let r = normalize_parens(&expr_to_string(&r_syn));
5107 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5108 }
5109 }
5110 _ => {
5111 let r = normalize_parens(&expr_to_string(&r_syn));
5112 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5113 }
5114 }
5115 }
5116
5117 fn build_expr_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
5119 let syn_expr = self.build_syn_expr(expr, info);
5120 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
5121 }
5122
5123 fn stmt_to_rust(&mut self, stmt: &Stmt, info: &MacroInferInfo) -> String {
5125 match stmt {
5126 Stmt::Expr(Some(expr), _) => {
5127 format!("{};", self.build_expr_string(expr, Some(info)))
5128 }
5129 Stmt::Expr(None, _) => ";".to_string(),
5130 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, "", Some(info)),
5131 Stmt::Return(None, _) => "return;".to_string(),
5132 _ => self.todo_marker("stmt")
5133 }
5134 }
5135
5136 fn type_name_to_rust(&mut self, type_name: &crate::ast::TypeName) -> String {
5138 let base_type = self.decl_specs_to_rust(&type_name.specs);
5140
5141 let mut result = if let Some(ref decl) = type_name.declarator {
5143 self.apply_derived_to_type(&base_type, &decl.derived)
5144 } else {
5145 base_type
5146 };
5147
5148 if type_name.specs.qualifiers.is_const {
5151 if let Some(pos) = result.rfind("*mut ") {
5152 result.replace_range(pos..pos + 5, "*const ");
5153 }
5154 }
5155
5156 result
5157 }
5158
5159 fn decl_specs_to_rust(&mut self, specs: &DeclSpecs) -> String {
5161 for spec in &specs.type_specs {
5163 if let TypeSpec::TypedefName(name) = spec {
5164 if let Some(generic_name) = self.current_type_param_map.get(name) {
5166 return generic_name.clone();
5167 }
5168 let name_str = self.interner.get(*name).to_string();
5169 if !self.known_symbols.contains(&name_str) {
5171 self.codegen_errors.push(format!("undefined type: {}", name_str));
5172 }
5173 return name_str;
5174 }
5175 }
5176
5177 let mut is_void = false;
5179 let mut is_char = false;
5180 let mut is_int = false;
5181 let mut is_short = false;
5182 let mut is_long = 0usize;
5183 let mut is_unsigned = false;
5184 let mut is_float = false;
5185 let mut is_double = false;
5186
5187 for spec in &specs.type_specs {
5188 match spec {
5189 TypeSpec::Void => is_void = true,
5190 TypeSpec::Char => is_char = true,
5191 TypeSpec::Int => is_int = true,
5192 TypeSpec::Short => is_short = true,
5193 TypeSpec::Long => is_long += 1,
5194 TypeSpec::Unsigned => is_unsigned = true,
5195 TypeSpec::Signed => {}
5196 TypeSpec::Float => is_float = true,
5197 TypeSpec::Double => is_double = true,
5198 TypeSpec::Bool => return "bool".to_string(),
5199 TypeSpec::Struct(spec) => {
5200 if let Some(n) = spec.name {
5201 return self.interner.get(n).to_string();
5202 } else {
5203 return self.type_marker().to_string();
5204 }
5205 }
5206 TypeSpec::Union(spec) => {
5207 if let Some(n) = spec.name {
5208 return self.interner.get(n).to_string();
5209 } else {
5210 return self.type_marker().to_string();
5211 }
5212 }
5213 TypeSpec::Enum(spec) => {
5214 if let Some(n) = spec.name {
5215 return self.interner.get(n).to_string();
5216 } else {
5217 return "c_int".to_string();
5218 }
5219 }
5220 _ => {}
5221 }
5222 }
5223
5224 if is_void {
5225 return "()".to_string();
5226 }
5227
5228 if is_float {
5229 return "c_float".to_string();
5230 }
5231
5232 if is_double {
5233 return if is_long > 0 { "c_longdouble".to_string() } else { "c_double".to_string() };
5234 }
5235
5236 if is_char {
5237 return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() };
5238 }
5239
5240 if is_short {
5241 return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() };
5242 }
5243
5244 if is_long >= 2 {
5245 return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() };
5246 }
5247
5248 if is_long == 1 {
5249 return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() };
5250 }
5251
5252 if is_int || is_unsigned {
5253 return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() };
5254 }
5255
5256 self.type_marker().to_string()
5257 }
5258
5259 fn apply_derived_to_type(&mut self, base: &str, derived: &[DerivedDecl]) -> String {
5261 let fn_idx = derived
5263 .iter()
5264 .position(|d| matches!(d, DerivedDecl::Function(_)));
5265
5266 if let Some(idx) = fn_idx {
5267 if let DerivedDecl::Function(param_list) = &derived[idx] {
5268 let is_fn_pointer =
5270 idx > 0 && matches!(derived[idx - 1], DerivedDecl::Pointer(_));
5271
5272 let return_end = if is_fn_pointer { idx - 1 } else { idx };
5274 let return_derived = &derived[..return_end];
5275 let return_type = self.apply_simple_derived(base, return_derived);
5276
5277 let params: Vec<_> = param_list
5279 .params
5280 .iter()
5281 .map(|p| self.param_type_only(p))
5282 .collect();
5283 let params_str = params.join(", ");
5284
5285 let fn_type =
5287 format!("unsafe extern \"C\" fn({}) -> {}", params_str, return_type);
5288
5289 if is_fn_pointer {
5291 return format!("Option<{}>", fn_type);
5292 }
5293 return fn_type;
5294 }
5295 }
5296
5297 self.apply_simple_derived(base, derived)
5299 }
5300
5301 fn apply_simple_derived(&self, base: &str, derived: &[DerivedDecl]) -> String {
5303 self.apply_simple_derived_with_specs_const(base, derived, false)
5304 }
5305
5306 fn apply_simple_derived_with_specs_const(&self, base: &str, derived: &[DerivedDecl], specs_is_const: bool) -> String {
5308 let mut result = base.to_string();
5309 let mut is_first_pointer = true;
5310 for d in derived.iter().rev() {
5311 match d {
5312 DerivedDecl::Pointer(quals) => {
5313 if result == "()" {
5315 result = "c_void".to_string();
5316 }
5317 let pointee_const = if is_first_pointer {
5321 specs_is_const
5322 } else {
5323 quals.is_const
5324 };
5325 if pointee_const {
5326 result = format!("*const {}", result);
5327 } else {
5328 result = format!("*mut {}", result);
5329 }
5330 is_first_pointer = false;
5331 }
5332 DerivedDecl::Array(arr) => {
5333 if result == "()" {
5335 result = "c_void".to_string();
5336 }
5337 if let Some(ref size_expr) = arr.size {
5338 if let ExprKind::IntLit(n) = &size_expr.kind {
5340 result = format!("[{}; {}]", result, n);
5341 } else {
5342 result = format!("*mut {}", result);
5343 }
5344 } else {
5345 result = format!("*mut {}", result);
5346 }
5347 }
5348 DerivedDecl::Function(_) => {
5349 }
5351 }
5352 }
5353 result
5354 }
5355
5356 fn param_type_only(&mut self, param: &ParamDecl) -> String {
5358 let ty = self.decl_specs_to_rust(¶m.specs);
5359 if let Some(ref declarator) = param.declarator {
5360 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5364 } else {
5365 ty
5366 }
5367 }
5368
5369 pub fn generate_inline_fn(mut self, name: crate::InternedStr, func_def: &FunctionDef) -> GeneratedCode {
5371 let name_str = self.interner.get(name);
5372
5373 let mut_params = {
5375 let mut all_names = HashSet::new();
5376 for d in &func_def.declarator.derived {
5378 if let DerivedDecl::Function(param_list) = d {
5379 for p in ¶m_list.params {
5380 if let Some(ref declarator) = p.declarator {
5381 if let Some(param_name) = declarator.name {
5382 all_names.insert(param_name);
5383 }
5384 }
5385 }
5386 }
5387 }
5388 for item in &func_def.body.items {
5390 if let BlockItem::Decl(decl) = item {
5391 for init_decl in &decl.declarators {
5392 if let Some(var_name) = init_decl.declarator.name {
5393 all_names.insert(var_name);
5394 }
5395 }
5396 }
5397 }
5398 let mut result = HashSet::new();
5399 for item in &func_def.body.items {
5400 if let BlockItem::Stmt(stmt) = item {
5401 collect_mut_params_from_stmt(stmt, &all_names, &mut result);
5402 }
5403 }
5404 result
5405 };
5406
5407 self.mut_local_names = mut_params.clone();
5409
5410 let params_str = self.build_fn_param_list(&func_def.declarator.derived, &mut_params);
5412
5413 let return_type = self.decl_specs_to_rust(&func_def.specs);
5415
5416 let return_derived: Vec<_> = func_def.declarator.derived.iter()
5420 .filter(|d| !matches!(d, DerivedDecl::Function(_)))
5421 .cloned()
5422 .collect();
5423 let return_type = self.apply_simple_derived_with_specs_const(&return_type, &return_derived, func_def.specs.qualifiers.is_const);
5424 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
5425
5426 for d in &func_def.declarator.derived {
5428 if let DerivedDecl::Function(param_list) = d {
5429 for p in ¶m_list.params {
5430 if let Some(ref declarator) = p.declarator {
5431 if let Some(param_name) = declarator.name {
5432 let ty = self.param_type_only(p);
5433 self.current_param_types.insert(param_name, UnifiedType::from_rust_str(&ty));
5434 self.current_local_names.insert(param_name);
5435 }
5436 }
5437 }
5438 }
5439 }
5440
5441 self.collect_local_names_recursive(&func_def.body);
5444
5445 let is_thx_dependent = self.perl_threaded
5447 && self.is_inline_fn_thx_dependent(&func_def.declarator.derived);
5448 let thx_info = if is_thx_dependent { " [THX]" } else { "" };
5449
5450 self.dump_ast_comment_for_body(name_str, &func_def.body);
5452
5453 self.writeln(&format!("/// {}{} - inline function", name_str, thx_info));
5455 self.writeln("#[inline]");
5456 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
5457
5458 self.writeln(&format!("pub unsafe fn {}({}) -> {} {{", name_str, params_str, return_type));
5460
5461 let needs_unsafe = func_def.function_call_count > 0 || func_def.deref_count > 0;
5463
5464 if needs_unsafe {
5465 self.writeln(" unsafe {");
5466 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5467 self.buffer.push_str(&body_str);
5468 self.writeln(" }");
5469 } else {
5470 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5471 self.buffer.push_str(&body_str);
5472 }
5473
5474 self.writeln("}");
5475 self.writeln("");
5476
5477 self.into_generated_code()
5478 }
5479
5480 fn build_fn_param_list(&mut self, derived: &[DerivedDecl], mut_params: &HashSet<InternedStr>) -> String {
5482 for d in derived {
5483 if let DerivedDecl::Function(param_list) = d {
5484 if is_void_only_param_list(¶m_list.params) {
5488 return String::new();
5489 }
5490 let params: Vec<_> = param_list.params.iter()
5491 .map(|p| self.param_decl_to_rust(p, mut_params))
5492 .collect();
5493 let mut result = params.join(", ");
5494 if param_list.is_variadic {
5495 if !result.is_empty() {
5496 result.push_str(", ");
5497 }
5498 result.push_str("...");
5499 }
5500 return result;
5501 }
5502 }
5503 String::new()
5504 }
5505
5506 fn is_inline_fn_thx_dependent(&self, derived: &[DerivedDecl]) -> bool {
5510 for d in derived {
5511 if let DerivedDecl::Function(param_list) = d {
5512 if let Some(first_param) = param_list.params.first() {
5513 if let Some(ref declarator) = first_param.declarator {
5514 if let Some(name) = declarator.name {
5515 let name_str = self.interner.get(name);
5516 return name_str == "my_perl";
5517 }
5518 }
5519 }
5520 return false;
5521 }
5522 }
5523 false
5524 }
5525
5526 fn param_decl_to_rust(&mut self, param: &ParamDecl, mut_params: &HashSet<InternedStr>) -> String {
5528 let param_name_interned = param.declarator
5529 .as_ref()
5530 .and_then(|d| d.name);
5531 let name = param_name_interned
5532 .map(|n| escape_rust_keyword(self.interner.get(n)))
5533 .unwrap_or_else(|| "_".to_string());
5534
5535 let ty = self.decl_specs_to_rust(¶m.specs);
5536
5537 let ty = if let Some(ref declarator) = param.declarator {
5539 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5540 } else {
5541 ty
5542 };
5543
5544 if let Some(n) = param_name_interned {
5546 self.current_param_types.insert(n, UnifiedType::from_rust_str(&ty));
5547 }
5548
5549 let mut_prefix = if param_name_interned.is_some_and(|n| mut_params.contains(&n)) {
5550 "mut "
5551 } else {
5552 ""
5553 };
5554
5555 format!("{}{}: {}", mut_prefix, name, ty)
5556 }
5557
5558 fn decl_to_rust_let(&mut self, decl: &Declaration, indent: &str) -> String {
5560 let mut result = String::new();
5561
5562 let base_type = self.decl_specs_to_rust(&decl.specs);
5564
5565 for init_decl in &decl.declarators {
5567 let name = init_decl.declarator.name
5568 .map(|n| escape_rust_keyword(self.interner.get(n)))
5569 .unwrap_or_else(|| "_".to_string());
5570
5571 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
5573
5574 if let Some(ref init) = init_decl.init {
5576 match init {
5577 Initializer::Expr(expr) => {
5578 let mut init_syn = self.build_syn_expr(expr, None);
5583 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5584 let decl_s = ty.clone();
5585 let expr_s = expr_ut.to_rust_string();
5586 let nd = normalize_integer_type(&decl_s);
5587 let ne = normalize_integer_type(&expr_s);
5588 if let (Some(d), Some(e)) = (nd, ne) {
5589 if !integer_types_compatible(d, e) {
5590 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, d);
5591 }
5592 }
5593 }
5594 let decl_is_mut_ptr = ty.contains("*mut ") && !ty.contains("*const ");
5599 let decl_is_const_ptr = ty.contains("*const ") && !ty.contains("*mut ");
5600 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5601 if expr_ut.is_pointer() {
5602 if decl_is_mut_ptr && expr_ut.is_const_pointer() {
5603 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5604 } else if decl_is_const_ptr && !expr_ut.is_const_pointer() {
5605 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5606 }
5607 }
5608 }
5609 let init_expr = normalize_parens(&crate::syn_codegen::expr_to_string(&init_syn));
5610 let init_expr = if is_null_literal(expr) && ty.contains("*mut") {
5612 "std::ptr::null_mut()".to_string()
5613 } else if is_null_literal(expr) && ty.contains("*const") {
5614 "std::ptr::null()".to_string()
5615 } else {
5616 init_expr
5617 };
5618 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5619 result.push_str(&format!("{}let {}{}: {} = {};\n", indent, mut_kw, name, ty, strip_outer_parens(&init_expr)));
5620 }
5621 Initializer::List(_) => {
5622 result.push_str(&format!("{}let {}: {} = /* init list */;\n", indent, name, ty));
5624 }
5625 }
5626 } else {
5627 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5629 result.push_str(&format!("{}let {}{}: {}; // uninitialized\n", indent, mut_kw, name, ty));
5630 }
5631 }
5632
5633 result
5634 }
5635
5636 fn compound_stmt_to_string(&mut self, stmt: &CompoundStmt, indent: &str) -> String {
5638 let mut result = String::new();
5639 for item in &stmt.items {
5640 match item {
5641 BlockItem::Decl(decl) => {
5642 self.collect_decl_types(decl);
5643 result.push_str(&self.decl_to_rust_let(decl, indent));
5644 }
5645 BlockItem::Stmt(s) => {
5646 let rust_stmt = self.stmt_to_rust_inline(s, indent);
5647 result.push_str(&rust_stmt);
5648 result.push('\n');
5649 }
5650 }
5651 }
5652 result
5653 }
5654
5655 fn stmt_to_rust_inline(&mut self, stmt: &Stmt, indent: &str) -> String {
5657 match stmt {
5658 Stmt::Expr(Some(expr), _) => {
5659 if let ExprKind::Assign { op, lhs, rhs } = &expr.kind {
5661 self.build_assign_stmt(op, lhs, rhs, indent, None)
5662 } else {
5663 format!("{}{};", indent, self.build_expr_string(expr, None))
5664 }
5665 }
5666 Stmt::Expr(None, _) => String::new(),
5667 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, indent, None),
5668 Stmt::Return(None, _) => format!("{}return;", indent),
5669 Stmt::If { cond, then_stmt, else_stmt, .. } => {
5670 let cond_str = self.build_expr_string(cond, None);
5671 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5673 let mut result = format!("{}if {} {{\n", indent, normalize_parens(&cond_bool));
5674 let nested_indent = format!("{} ", indent);
5675 result.push_str(&self.stmt_to_rust_inline(then_stmt, &nested_indent));
5676 result.push_str("\n");
5677 result.push_str(&format!("{}}}", indent));
5678 if let Some(else_stmt) = else_stmt {
5679 result.push_str(" else {\n");
5680 result.push_str(&self.stmt_to_rust_inline(else_stmt, &nested_indent));
5681 result.push_str("\n");
5682 result.push_str(&format!("{}}}", indent));
5683 }
5684 result
5685 }
5686 Stmt::Compound(compound) => {
5687 let mut result = format!("{}{{\n", indent);
5688 for item in &compound.items {
5689 match item {
5690 BlockItem::Stmt(s) => {
5691 let nested_indent = format!("{} ", indent);
5692 result.push_str(&self.stmt_to_rust_inline(s, &nested_indent));
5693 result.push_str("\n");
5694 }
5695 BlockItem::Decl(decl) => {
5696 self.collect_decl_types(decl);
5697 let nested_indent = format!("{} ", indent);
5698 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5699 }
5700 }
5701 }
5702 result.push_str(&format!("{}}}", indent));
5703 result
5704 }
5705 Stmt::While { cond, body, .. } => {
5706 let cond_str = self.build_expr_string(cond, None);
5707 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5709 let mut result = format!("{}while {} {{\n", indent, cond_bool);
5710 let nested_indent = format!("{} ", indent);
5711 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5712 result.push_str("\n");
5713 result.push_str(&format!("{}}}", indent));
5714 result
5715 }
5716 Stmt::For { init, cond, step, body, .. } => {
5717 let mut result = format!("{}{{\n", indent);
5718 let nested_indent = format!("{} ", indent);
5719
5720 if let Some(for_init) = init {
5722 match for_init {
5723 ForInit::Expr(expr) => {
5724 result.push_str(&format!("{}{};\n", nested_indent, self.build_expr_string(expr, None)));
5725 }
5726 ForInit::Decl(decl) => {
5727 self.collect_decl_types(decl);
5728 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5729 }
5730 }
5731 }
5732
5733 if let Some(cond_expr) = cond {
5735 let cond_str = self.build_expr_string(cond_expr, None);
5736 let cond_bool = self.wrap_as_bool_condition_inline(cond_expr, &cond_str);
5738 result.push_str(&format!("{}while {} {{\n", nested_indent, cond_bool));
5739 } else {
5740 result.push_str(&format!("{}loop {{\n", nested_indent));
5741 }
5742
5743 let body_indent = format!("{} ", nested_indent);
5744
5745 result.push_str(&self.stmt_to_rust_inline(body, &body_indent));
5747 result.push_str("\n");
5748
5749 if let Some(step_expr) = step {
5751 result.push_str(&format!("{}{};\n", body_indent, self.build_expr_string(step_expr, None)));
5752 }
5753
5754 result.push_str(&format!("{}}}\n", nested_indent));
5755 result.push_str(&format!("{}}}", indent));
5756 result
5757 }
5758 Stmt::DoWhile { body, cond, .. } => {
5759 if is_zero_constant(cond) {
5762 if !stmt_contains_top_level_break(body) {
5767 let mut result = format!("{}{{\n", indent);
5768 let nested_indent = format!("{} ", indent);
5769 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5770 result.push_str("\n");
5771 result.push_str(&format!("{}}}", indent));
5772 return result;
5773 }
5774 let mut result = format!("{}loop {{\n", indent);
5775 let nested_indent = format!("{} ", indent);
5776 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5777 result.push_str("\n");
5778 result.push_str(&format!("{} break;\n", indent));
5779 result.push_str(&format!("{}}}", indent));
5780 return result;
5781 }
5782
5783 let mut result = format!("{}loop {{\n", indent);
5785 let nested_indent = format!("{} ", indent);
5786 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5787 result.push_str("\n");
5788 let cond_str = self.build_expr_string(cond, None);
5789 let break_cond = if is_boolean_expr(cond) {
5793 normalize_parens(&format!("!({})", cond_str))
5794 } else {
5795 format!("{} == 0", cond_str)
5796 };
5797 result.push_str(&format!("{} if {} {{ break; }}\n", indent, break_cond));
5798 result.push_str(&format!("{}}}", indent));
5799 result
5800 }
5801 Stmt::Switch { expr, body, .. } => {
5802 let expr_str = self.build_expr_string(expr, None);
5803 let mut result = format!("{}match {} {{\n", indent, expr_str);
5804 let nested_indent = format!("{} ", indent);
5805
5806 self.collect_switch_cases(body, &nested_indent, &mut result);
5808
5809 result.push_str(&format!("{}}}", indent));
5810 result
5811 }
5812 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5813 let case_val = self.build_expr_string(case_expr, None);
5815 let mut result = format!("{}{} => {{\n", indent, case_val);
5816 let body_indent = format!("{} ", indent);
5817 result.push_str(&self.stmt_to_rust_inline(case_stmt, &body_indent));
5818 result.push_str("\n");
5819 result.push_str(&format!("{}}}", indent));
5820 result
5821 }
5822 Stmt::Default { stmt: default_stmt, .. } => {
5823 let mut result = format!("{}_ => {{\n", indent);
5824 let body_indent = format!("{} ", indent);
5825 result.push_str(&self.stmt_to_rust_inline(default_stmt, &body_indent));
5826 result.push_str("\n");
5827 result.push_str(&format!("{}}}", indent));
5828 result
5829 }
5830 Stmt::Goto(label, _) => {
5831 let label_str = self.interner.get(*label);
5832 format!("{}break '{}; // goto", indent, label_str)
5833 }
5834 Stmt::Label { name, stmt: label_stmt, .. } => {
5835 let label_str = self.interner.get(*name);
5836 let mut result = format!("{}'{}: {{\n", indent, label_str);
5837 let nested_indent = format!("{} ", indent);
5838 result.push_str(&self.stmt_to_rust_inline(label_stmt, &nested_indent));
5839 result.push_str("\n");
5840 result.push_str(&format!("{}}}", indent));
5841 result
5842 }
5843 Stmt::Break(_) => format!("{}break;", indent),
5844 Stmt::Continue(_) => format!("{}continue;", indent),
5845 _ => self.todo_marker(&format!("{:?}", std::mem::discriminant(stmt)))
5846 }
5847 }
5848
5849 fn collect_switch_cases(&mut self, stmt: &Stmt, indent: &str, result: &mut String) {
5851 struct SwitchCase {
5853 patterns: Vec<String>, body_stmts: Vec<String>,
5855 is_default: bool,
5856 }
5857
5858 let mut cases: Vec<SwitchCase> = Vec::new();
5859 let body_indent = format!("{} ", indent);
5860
5861 fn collect_items<'a>(stmt: &'a Stmt, items: &mut Vec<&'a BlockItem>) {
5863 if let Stmt::Compound(compound) = stmt {
5864 for item in &compound.items {
5865 items.push(item);
5866 }
5867 }
5868 }
5869
5870 fn flatten_case_chain<'a>(stmt: &'a Stmt, patterns: &mut Vec<&'a Expr>) -> (&'a Stmt, bool) {
5872 match stmt {
5873 Stmt::Case { expr, stmt: inner_stmt, .. } => {
5874 patterns.push(expr);
5875 flatten_case_chain(inner_stmt, patterns)
5876 }
5877 Stmt::Default { stmt: inner_stmt, .. } => {
5878 (inner_stmt, true)
5880 }
5881 other => (other, false)
5882 }
5883 }
5884
5885 let mut items: Vec<&BlockItem> = Vec::new();
5886 collect_items(stmt, &mut items);
5887
5888 for item in items {
5889 match item {
5890 BlockItem::Stmt(s) => {
5891 match s {
5892 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5893 let mut patterns: Vec<&Expr> = vec![case_expr];
5895 let (final_stmt, has_default) = flatten_case_chain(case_stmt, &mut patterns);
5896
5897 let pattern_strs: Vec<String> = patterns.iter()
5899 .map(|e| self.expr_to_rust_pattern(e))
5900 .collect();
5901
5902 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
5904 vec![]
5905 } else {
5906 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
5907 };
5908 cases.push(SwitchCase {
5909 patterns: pattern_strs,
5910 body_stmts,
5911 is_default: has_default,
5912 });
5913 }
5914 Stmt::Default { stmt: default_stmt, .. } => {
5915 let mut patterns: Vec<&Expr> = Vec::new();
5917 let (final_stmt, _) = flatten_case_chain(default_stmt, &mut patterns);
5918
5919 let pattern_strs: Vec<String> = patterns.iter()
5921 .map(|e| self.expr_to_rust_pattern(e))
5922 .collect();
5923
5924 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
5926 vec![]
5927 } else {
5928 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
5929 };
5930 cases.push(SwitchCase {
5931 patterns: pattern_strs,
5932 body_stmts,
5933 is_default: true,
5934 });
5935 }
5936 Stmt::Break(_) => {
5937 }
5940 other => {
5941 if let Some(last) = cases.last_mut() {
5943 last.body_stmts.push(self.stmt_to_rust_inline(other, &body_indent));
5944 }
5945 }
5947 }
5948 }
5949 BlockItem::Decl(decl) => {
5950 self.collect_decl_types(decl);
5951 if let Some(last) = cases.last_mut() {
5953 last.body_stmts.push(self.decl_to_rust_let(decl, &body_indent));
5954 }
5955 }
5956 }
5957 }
5958
5959 let has_default = cases.iter().any(|c| c.is_default);
5961 for case in &cases {
5962 let pattern = if case.is_default {
5963 if case.patterns.is_empty() {
5964 "_".to_string()
5965 } else {
5966 format!("{} | _", case.patterns.join(" | "))
5968 }
5969 } else {
5970 case.patterns.join(" | ")
5971 };
5972
5973 result.push_str(&format!("{}{} => {{\n", indent, pattern));
5974 for stmt in &case.body_stmts {
5975 result.push_str(stmt);
5976 result.push_str("\n");
5977 }
5978 result.push_str(&format!("{}}}\n", indent));
5979 }
5980 if !has_default {
5984 result.push_str(&format!("{}_ => {{}}\n", indent));
5985 }
5986 }
5987
5988 fn expr_to_field_path(&self, expr: &Expr) -> Option<String> {
5992 match &expr.kind {
5993 ExprKind::Ident(name) => {
5994 Some(self.interner.get(*name).to_string())
5995 }
5996 ExprKind::Member { expr: base, member } => {
5997 let base_path = self.expr_to_field_path(base)?;
5998 let member_name = self.interner.get(*member);
5999 Some(format!("{}.{}", base_path, member_name))
6000 }
6001 _ => None,
6002 }
6003 }
6004
6005
6006 fn expr_to_rust_pattern(&mut self, expr: &Expr) -> String {
6012 match &expr.kind {
6013 ExprKind::Ident(name) => {
6014 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
6016 let enum_str = self.interner.get(enum_name);
6017 let variant_str = self.interner.get(*name);
6018 format!("crate::{}::{}", enum_str, variant_str)
6019 } else {
6020 escape_rust_keyword(self.interner.get(*name))
6021 }
6022 }
6023 _ => self.build_expr_string(expr, None)
6025 }
6026 }
6027}
6028
6029impl<'a, W: Write> CodegenDriver<'a, W> {
6030 pub fn new(
6032 writer: W,
6033 interner: &'a StringInterner,
6034 enum_dict: &'a EnumDict,
6035 macro_ctx: &'a MacroInferContext,
6036 bindings_info: BindingsInfo,
6037 config: CodegenConfig,
6038 ) -> Self {
6039 Self {
6040 writer,
6041 interner,
6042 enum_dict,
6043 macro_ctx,
6044 bindings_info,
6045 config,
6046 stats: CodegenStats::default(),
6047 used_libc_fns: HashSet::new(),
6048 successfully_generated_inlines: HashSet::new(),
6049 generatable_macros: HashSet::new(),
6050 const_pointer_params: HashMap::new(),
6051 bool_return_macros: HashSet::new(),
6052 perl_threaded: true,
6055 }
6056 }
6057
6058 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
6060 self.perl_threaded = threaded;
6061 self
6062 }
6063
6064 pub fn stats(&self) -> &CodegenStats {
6066 &self.stats
6067 }
6068
6069 pub fn generate(&mut self, result: &InferResult) -> io::Result<()> {
6074 self.perl_threaded = result.perl_build_mode.is_threaded();
6076
6077 let missing_structs = crate::struct_emitter::emit_missing_structs(
6080 &result.fields_dict,
6081 result.rust_decl_dict.as_ref(),
6082 self.interner,
6083 );
6084 let static_arrays = crate::static_array_emitter::emit_static_arrays(
6085 &result.global_const_dict,
6086 &result.fields_dict,
6087 result.rust_decl_dict.as_ref(),
6088 self.interner,
6089 );
6090 for n in &static_arrays.emitted_names {
6094 self.bindings_info.static_arrays.insert(n.clone());
6095 }
6096 for (n, t) in &static_arrays.emitted_types {
6097 self.bindings_info.static_types.insert(n.clone(), t.clone());
6098 }
6099
6100 let mut known_symbols = KnownSymbols::new(result, self.interner);
6102 for n in &missing_structs.emitted_struct_names {
6103 known_symbols.insert(n.clone());
6104 }
6105 for n in &missing_structs.emitted_typedef_names {
6106 known_symbols.insert(n.clone());
6107 }
6108
6109 for (struct_name, methods) in &missing_structs.bitfield_methods {
6113 self.bindings_info
6114 .bitfield_methods
6115 .entry(struct_name.clone())
6116 .or_default()
6117 .extend(methods.iter().cloned());
6118 }
6119 writeln!(self.writer, "// Auto-generated Rust bindings")?;
6124 writeln!(self.writer, "// Generated by libperl-macrogen")?;
6127 writeln!(self.writer)?;
6128
6129 self.generate_use_statements()?;
6131
6132 self.generate_enum_imports(result)?;
6134
6135 if !missing_structs.source.is_empty() {
6137 self.writer.write_all(missing_structs.source.as_bytes())?;
6138 }
6139
6140 if !static_arrays.source.is_empty() {
6142 self.writer.write_all(static_arrays.source.as_bytes())?;
6143 }
6144
6145 self.precompute_macro_generability(result, &known_symbols);
6147
6148 for (&name, info) in &result.infer_ctx.macros {
6150 if info.is_bool_return {
6151 self.bool_return_macros.insert(name);
6152 }
6153 }
6154
6155 if self.config.emit_inline_fns {
6157 self.generate_inline_fns(result, &known_symbols)?;
6158 }
6159
6160 if self.config.emit_macros {
6162 self.generate_macros(result, &known_symbols)?;
6163 }
6164
6165 if !self.used_libc_fns.is_empty() {
6167 let mut fns: Vec<_> = self.used_libc_fns.iter().cloned().collect();
6168 fns.sort();
6169 writeln!(self.writer, "use libc::{{{}}};", fns.join(", "))?;
6170 }
6171
6172 Ok(())
6173 }
6174
6175 fn generate_use_statements(&mut self) -> io::Result<()> {
6177 let statements = if self.config.use_statements.is_empty() {
6178 CodegenConfig::default_use_statements()
6179 } else {
6180 self.config.use_statements.clone()
6181 };
6182
6183 if !statements.is_empty() {
6184 for stmt in &statements {
6185 writeln!(self.writer, "{};", stmt)?;
6186 }
6187 writeln!(self.writer)?;
6188 }
6189
6190 Ok(())
6191 }
6192
6193 fn generate_enum_imports(&mut self, result: &InferResult) -> io::Result<()> {
6197 let enum_names = result.enum_dict.target_enum_names(self.interner);
6198 let bindings_enums = result.rust_decl_dict.as_ref().map(|d| &d.enums);
6199
6200 let filtered_names: Vec<_> = enum_names
6202 .into_iter()
6203 .filter(|name| {
6204 bindings_enums.map_or(true, |enums| enums.contains(*name))
6205 })
6206 .collect();
6207
6208 if !filtered_names.is_empty() {
6209 writeln!(self.writer, "// Enum variant imports")?;
6210 for name in filtered_names {
6211 writeln!(self.writer, "#[allow(unused_imports)]")?;
6212 writeln!(self.writer, "use crate::{}::*;", name)?;
6213 }
6214 writeln!(self.writer)?;
6215 }
6216
6217 Ok(())
6218 }
6219
6220 fn precompute_macro_generability(&mut self, result: &InferResult, known_symbols: &KnownSymbols) {
6226 let macros: Vec<_> = result.infer_ctx.macros.iter()
6228 .filter(|(_, info)| self.should_include_macro(info))
6229 .collect();
6230 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6231
6232 let sorted_names = self.topological_sort_macros(¯os);
6234
6235 for name in sorted_names {
6236 let info = result.infer_ctx.macros.get(&name).unwrap();
6237
6238 if info.apidoc_suppressed {
6244 continue;
6245 }
6246
6247 let has_cascade_failure = info.called_functions.iter().any(|called| {
6252 if included_set.contains(called) {
6253 return result.infer_ctx.macros.get(called)
6254 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6255 .unwrap_or(false)
6256 && !self.generatable_macros.contains(called);
6257 }
6258 false
6259 });
6260 if has_cascade_failure {
6261 continue;
6262 }
6263
6264 let status = self.get_macro_status(info);
6266 if status == GenerateStatus::Success {
6267 let codegen = RustCodegen::new(
6269 self.interner, self.enum_dict, self.macro_ctx,
6270 self.bindings_info.clone(), &known_symbols,
6271 result.rust_decl_dict.as_ref(), Some(&result.inline_fn_dict),
6272 ).with_perl_threaded(self.perl_threaded);
6273 let generated = codegen.generate_macro(info);
6274 if generated.is_complete() && !generated.has_unresolved_names() {
6275 self.generatable_macros.insert(name);
6276 }
6277 }
6278 }
6279 }
6280
6281 pub fn generate_inline_fns(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6288 writeln!(self.writer, "// =============================================================================")?;
6289 writeln!(self.writer, "// Inline Functions")?;
6290 writeln!(self.writer, "// =============================================================================")?;
6291 writeln!(self.writer)?;
6292
6293 let mut fns: Vec<_> = result.inline_fn_dict.iter()
6295 .filter(|(_, func_def)| func_def.is_target)
6296 .collect();
6297 fns.sort_by_key(|(name, _)| self.interner.get(**name));
6298
6299 let inline_set: HashSet<InternedStr> = fns.iter().map(|(n, _)| **n).collect();
6301
6302 enum InlineGenResult {
6304 CallsUnavailable,
6305 ContainsGoto,
6306 UnresolvedNames { code: String, unresolved: Vec<String> },
6307 CodegenError { code: String, errors: Vec<String> },
6308 Incomplete { code: String },
6309 Success { code: String, used_libc: HashSet<String> },
6310 Suppressed { reason: String },
6311 }
6312
6313 let mut gen_results: Vec<(InternedStr, InlineGenResult)> = Vec::new();
6314
6315 for (name, func_def) in &fns {
6316 if result.inline_fn_dict.is_apidoc_suppressed(**name) {
6319 let n_str = self.interner.get(**name);
6320 let reason = result.apidoc_patches.skip_reason(n_str)
6321 .unwrap_or("apidoc skip_codegen")
6322 .to_string();
6323 gen_results.push((**name,
6324 InlineGenResult::Suppressed { reason }));
6325 continue;
6326 }
6327
6328 if result.inline_fn_dict.is_calls_unavailable(**name) {
6330 gen_results.push((**name, InlineGenResult::CallsUnavailable));
6331 continue;
6332 }
6333
6334 if block_items_contain_goto(&func_def.body.items) {
6335 gen_results.push((**name, InlineGenResult::ContainsGoto));
6336 continue;
6337 }
6338
6339 let codegen = RustCodegen::new(self.interner, self.enum_dict, self.macro_ctx, self.bindings_info.clone(), known_symbols, result.rust_decl_dict.as_ref(), Some(&result.inline_fn_dict))
6340 .with_perl_threaded(self.perl_threaded)
6341 .with_dump_ast_for(self.config.dump_ast_for.clone())
6342 .with_dump_types_for(self.config.dump_types_for.clone())
6343 .with_fields_dict(&result.fields_dict)
6344 .with_bool_return(false, self.bool_return_macros.clone());
6345 let generated = codegen.generate_inline_fn(**name, func_def);
6346
6347 if generated.has_unresolved_names() {
6348 gen_results.push((**name, InlineGenResult::UnresolvedNames {
6349 code: generated.code,
6350 unresolved: generated.unresolved_names,
6351 }));
6352 } else if !generated.codegen_errors.is_empty() {
6353 gen_results.push((**name, InlineGenResult::CodegenError {
6354 code: generated.code,
6355 errors: generated.codegen_errors,
6356 }));
6357 } else if generated.is_complete() {
6358 gen_results.push((**name, InlineGenResult::Success {
6359 code: generated.code,
6360 used_libc: generated.used_libc_fns,
6361 }));
6362 } else {
6363 gen_results.push((**name, InlineGenResult::Incomplete {
6364 code: generated.code,
6365 }));
6366 }
6367 }
6368
6369 for (name, gen_result) in &gen_results {
6371 if matches!(gen_result, InlineGenResult::Success { .. }) {
6372 self.successfully_generated_inlines.insert(*name);
6373 }
6374 }
6375
6376 let mut changed = true;
6381 while changed {
6382 changed = false;
6383 let current_success = self.successfully_generated_inlines.clone();
6384 for (name, _) in &gen_results {
6385 if !current_success.contains(name) {
6386 continue;
6387 }
6388 if let Some(calls) = result.inline_fn_dict.get_called_functions(*name) {
6389 let has_unavailable = calls.iter().any(|called| {
6390 if inline_set.contains(called) && !current_success.contains(called) {
6392 return true;
6393 }
6394 if let Some(macro_info) = result.infer_ctx.macros.get(called) {
6396 if macro_info.is_target && self.should_include_macro(macro_info) {
6397 if !self.generatable_macros.contains(called) {
6398 return true;
6399 }
6400 }
6401 }
6402 false
6403 });
6404 if has_unavailable {
6405 self.successfully_generated_inlines.remove(name);
6406 changed = true;
6407 }
6408 }
6409 }
6410 }
6411
6412 for (name, gen_result) in gen_results {
6414 match gen_result {
6415 InlineGenResult::CallsUnavailable => {
6416 let name_str = self.interner.get(name);
6417 let calls = result.inline_fn_dict.get_called_functions(name);
6418 let absent: Vec<String> = calls
6421 .map(|cs| cs.iter()
6422 .filter(|c| {
6423 let fn_name = self.interner.get(**c);
6424 !self.is_function_available(**c, fn_name, result)
6425 })
6426 .map(|c| self.interner.get(*c).to_string())
6427 .collect())
6428 .unwrap_or_default();
6429 let cascade_deps: Vec<String> = calls
6430 .map(|cs| cs.iter()
6431 .filter(|c| {
6432 let is_unavailable_inline = result.inline_fn_dict.get(**c).is_some()
6433 && result.inline_fn_dict.is_unavailable_for_codegen(**c);
6434 let is_unavailable_macro = result.infer_ctx.macros.get(c)
6435 .map(|info| info.is_unavailable_for_codegen())
6436 .unwrap_or(false);
6437 is_unavailable_inline || is_unavailable_macro
6438 })
6439 .map(|c| self.interner.get(*c).to_string())
6440 .collect())
6441 .unwrap_or_default();
6442 let mut cascade_deps = cascade_deps;
6444 cascade_deps.sort();
6445 let mut absent = absent;
6446 absent.sort();
6447 if absent.is_empty() {
6448 writeln!(self.writer,
6449 "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6450 name_str, cascade_deps.join(", "))?;
6451 } else {
6452 writeln!(self.writer,
6453 "// [CALLS_UNAVAILABLE] {} - calls unavailable function(s): {}",
6454 name_str, absent.join(", "))?;
6455 }
6456 writeln!(self.writer)?;
6457 self.stats.inline_fns_cascade_unavailable += 1;
6458 }
6459 InlineGenResult::ContainsGoto => {
6460 let name_str = self.interner.get(name);
6461 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6462 writeln!(self.writer)?;
6463 self.stats.inline_fns_contains_goto += 1;
6464 }
6465 InlineGenResult::Suppressed { reason } => {
6466 let name_str = self.interner.get(name);
6467 writeln!(self.writer,
6468 "// [CODEGEN_SUPPRESSED] {} - inline function (apidoc patch)",
6469 name_str)?;
6470 writeln!(self.writer, "// Reason: {}", reason)?;
6471 writeln!(self.writer)?;
6472 }
6473 InlineGenResult::UnresolvedNames { code, unresolved } => {
6474 let name_str = self.interner.get(name);
6475 let mut unresolved = unresolved.clone();
6476 unresolved.sort(); writeln!(self.writer, "// [UNRESOLVED_NAMES] {} - inline function", name_str)?;
6478 writeln!(self.writer, "// Unresolved: {}", unresolved.join(", "))?;
6479 for line in code.lines() {
6480 writeln!(self.writer, "// {}", line)?;
6481 }
6482 writeln!(self.writer)?;
6483 self.stats.inline_fns_unresolved_names += 1;
6484 }
6485 InlineGenResult::CodegenError { code, errors } => {
6486 let name_str = self.interner.get(name);
6487 writeln!(self.writer, "// [CODEGEN_ERROR] {} - inline function", name_str)?;
6488 for err in &errors {
6489 writeln!(self.writer, "// {}", err)?;
6490 }
6491 for line in code.lines() {
6492 writeln!(self.writer, "// {}", line)?;
6493 }
6494 writeln!(self.writer)?;
6495 }
6496 InlineGenResult::Incomplete { code } => {
6497 let name_str = self.interner.get(name);
6498 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {} - inline function", name_str)?;
6499 for line in code.lines() {
6500 writeln!(self.writer, "// {}", line)?;
6501 }
6502 writeln!(self.writer)?;
6503 self.stats.inline_fns_type_incomplete += 1;
6504 }
6505 InlineGenResult::Success { code, used_libc } => {
6506 if self.successfully_generated_inlines.contains(&name) {
6507 write!(self.writer, "{}", code)?;
6509 self.used_libc_fns.extend(used_libc.iter().cloned());
6510 self.stats.inline_fns_success += 1;
6511 } else {
6512 let name_str = self.interner.get(name);
6514 let mut unavailable: Vec<String> = result.inline_fn_dict.get_called_functions(name)
6515 .map(|calls| calls.iter()
6516 .filter(|c| inline_set.contains(c) && !self.successfully_generated_inlines.contains(c))
6517 .map(|c| self.interner.get(*c).to_string())
6518 .collect())
6519 .unwrap_or_default();
6520 unavailable.sort(); writeln!(self.writer, "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6522 name_str, unavailable.join(", "))?;
6523 for line in code.lines() {
6524 writeln!(self.writer, "// {}", line)?;
6525 }
6526 writeln!(self.writer)?;
6527 self.stats.inline_fns_cascade_unavailable += 1;
6528 }
6529 }
6530 }
6531 }
6532
6533 writeln!(self.writer)?;
6534 Ok(())
6535 }
6536
6537 pub fn generate_macros(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6539 writeln!(self.writer, "// =============================================================================")?;
6540 writeln!(self.writer, "// Macro Functions")?;
6541 writeln!(self.writer, "// =============================================================================")?;
6542 writeln!(self.writer)?;
6543
6544 let macros: Vec<_> = result.infer_ctx.macros.iter()
6546 .filter(|(_, info)| self.should_include_macro(info))
6547 .collect();
6548 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6549
6550 let sorted_names = self.topological_sort_macros(¯os);
6552
6553 let mut callee_const_params: HashMap<InternedStr, HashSet<usize>> = HashMap::new();
6557 let mut bool_return_macros: HashSet<InternedStr> = HashSet::new();
6558 for (&name, info) in &result.infer_ctx.macros {
6559 if !info.const_pointer_positions.is_empty() {
6560 callee_const_params.insert(name, info.const_pointer_positions.clone());
6561 }
6562 if info.is_bool_return {
6563 bool_return_macros.insert(name);
6564 }
6565 }
6566 self.const_pointer_params = callee_const_params;
6567 self.bool_return_macros = bool_return_macros;
6568
6569 let mut successfully_generated: HashSet<InternedStr> = HashSet::new();
6571
6572 for name in sorted_names {
6573 let info = result.infer_ctx.macros.get(&name).unwrap();
6574
6575 if info.apidoc_suppressed {
6579 let name_str_for_patch = self.interner.get(name);
6580 let reason = result.apidoc_patches.skip_reason(name_str_for_patch)
6581 .unwrap_or("apidoc skip_codegen");
6582 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6583 writeln!(self.writer,
6584 "// [CODEGEN_SUPPRESSED] {}{} - macro function (apidoc patch)",
6585 name_str_for_patch, thx_info)?;
6586 writeln!(self.writer, "// Reason: {}", reason)?;
6587 writeln!(self.writer)?;
6588 continue;
6589 }
6590
6591 let unavailable_deps: Vec<String> = info.called_functions.iter()
6597 .filter(|called| {
6598 if included_set.contains(called) {
6600 return result.infer_ctx.macros.get(called)
6601 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6602 .unwrap_or(false)
6603 && !successfully_generated.contains(called);
6604 }
6605 if result.inline_fn_dict.get(**called)
6607 .map(|f| f.is_target)
6608 .unwrap_or(false)
6609 {
6610 return !self.successfully_generated_inlines.contains(called);
6611 }
6612 false
6613 })
6614 .map(|called| self.interner.get(*called).to_string())
6615 .collect();
6616
6617 if !unavailable_deps.is_empty() {
6618 self.generate_macro_cascade_unavailable(info, &unavailable_deps)?;
6619 self.stats.macros_cascade_unavailable += 1;
6620 continue;
6621 }
6622
6623 let status = self.get_macro_status(info);
6625 match status {
6626 GenerateStatus::Success => {
6627 let const_positions = self.const_pointer_params.get(&name)
6629 .cloned().unwrap_or_default();
6630 let is_bool = self.bool_return_macros.contains(&name);
6631 let codegen = RustCodegen::new(self.interner, self.enum_dict, self.macro_ctx, self.bindings_info.clone(), known_symbols, result.rust_decl_dict.as_ref(), Some(&result.inline_fn_dict))
6632 .with_perl_threaded(self.perl_threaded)
6633 .with_dump_ast_for(self.config.dump_ast_for.clone())
6634 .with_dump_types_for(self.config.dump_types_for.clone())
6635 .with_fields_dict(&result.fields_dict)
6636 .with_const_pointer_positions(const_positions)
6637 .with_bool_return(is_bool, self.bool_return_macros.clone());
6638 let generated = codegen.generate_macro(info);
6639
6640 if generated.has_unresolved_names() {
6641 let name_str = self.interner.get(info.name);
6643 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6644 writeln!(self.writer, "// [UNRESOLVED_NAMES] {}{} - macro function", name_str, thx_info)?;
6645 writeln!(self.writer, "// Unresolved: {}", generated.unresolved_names.join(", "))?;
6646 for line in generated.code.lines() {
6647 writeln!(self.writer, "// {}", line)?;
6648 }
6649 writeln!(self.writer)?;
6650 self.stats.macros_unresolved_names += 1;
6651 } else if !generated.codegen_errors.is_empty() {
6652 let name_str = self.interner.get(info.name);
6654 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6655 writeln!(self.writer, "// [CODEGEN_ERROR] {}{} - macro function", name_str, thx_info)?;
6656 for err in &generated.codegen_errors {
6657 writeln!(self.writer, "// {}", err)?;
6658 }
6659 for line in generated.code.lines() {
6660 writeln!(self.writer, "// {}", line)?;
6661 }
6662 writeln!(self.writer)?;
6663 } else if generated.is_complete() {
6664 write!(self.writer, "{}", generated.code)?;
6666 self.used_libc_fns.extend(generated.used_libc_fns.iter().cloned());
6667 self.stats.macros_success += 1;
6668 successfully_generated.insert(name);
6669 } else {
6670 let name_str = self.interner.get(info.name);
6672 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6673 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {}{} - macro function", name_str, thx_info)?;
6674 for line in generated.code.lines() {
6675 writeln!(self.writer, "// {}", line)?;
6676 }
6677 writeln!(self.writer)?;
6678 self.stats.macros_type_incomplete += 1;
6679 }
6680 }
6681 GenerateStatus::ParseFailed => {
6682 self.generate_macro_parse_failed(info)?;
6683 self.stats.macros_parse_failed += 1;
6684 }
6685 GenerateStatus::TypeIncomplete => {
6686 self.generate_macro_type_incomplete(info, result)?;
6687 self.stats.macros_type_incomplete += 1;
6688 }
6689 GenerateStatus::CallsUnavailable => {
6690 let absent: Vec<&str> = info.called_functions.iter()
6694 .filter(|fn_id| {
6695 let fn_name = self.interner.get(**fn_id);
6696 !self.is_function_available(**fn_id, fn_name, result)
6697 })
6698 .map(|fn_id| self.interner.get(*fn_id))
6699 .collect();
6700 if absent.is_empty() {
6701 let cascade_deps: Vec<String> = info.called_functions.iter()
6703 .filter(|fn_id| {
6704 if let Some(m) = result.infer_ctx.macros.get(*fn_id) {
6705 return m.is_unavailable_for_codegen();
6706 }
6707 if result.inline_fn_dict.get(**fn_id).is_some() {
6708 return result.inline_fn_dict
6709 .is_unavailable_for_codegen(**fn_id);
6710 }
6711 false
6712 })
6713 .map(|fn_id| self.interner.get(*fn_id).to_string())
6714 .collect();
6715 self.generate_macro_cascade_unavailable(info, &cascade_deps)?;
6716 self.stats.macros_cascade_unavailable += 1;
6717 } else {
6718 self.generate_macro_calls_unavailable(info, result)?;
6719 self.stats.macros_calls_unavailable += 1;
6720 }
6721 }
6722 GenerateStatus::ContainsGoto => {
6723 let name_str = self.interner.get(info.name);
6724 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6725 writeln!(self.writer)?;
6726 }
6727 GenerateStatus::GenericUnsupported => {
6728 let name_str = self.interner.get(info.name);
6729 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6730 writeln!(self.writer, "// [GENERIC_UNSUPPORTED] {}{} - Rust cannot cast to generic type T", name_str, thx_info)?;
6731 let const_positions = self.const_pointer_params.get(&name)
6733 .cloned().unwrap_or_default();
6734 let is_bool = self.bool_return_macros.contains(&name);
6735 let codegen = RustCodegen::new(self.interner, self.enum_dict, self.macro_ctx, self.bindings_info.clone(), known_symbols, result.rust_decl_dict.as_ref(), Some(&result.inline_fn_dict))
6736 .with_perl_threaded(self.perl_threaded)
6737 .with_fields_dict(&result.fields_dict)
6738 .with_const_pointer_positions(const_positions)
6739 .with_bool_return(is_bool, self.bool_return_macros.clone());
6740 let generated = codegen.generate_macro(info);
6741 for line in generated.code.lines() {
6742 writeln!(self.writer, "// {}", line)?;
6743 }
6744 writeln!(self.writer)?;
6745 self.stats.macros_generic_unsupported += 1;
6746 }
6747 GenerateStatus::Skip => {
6748 }
6750 }
6751 }
6752
6753 Ok(())
6754 }
6755
6756 fn topological_sort_macros(
6760 &self,
6761 macros: &[(&InternedStr, &MacroInferInfo)],
6762 ) -> Vec<InternedStr> {
6763 use std::collections::VecDeque;
6764
6765 let macro_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6766
6767 let mut in_degree: HashMap<InternedStr, usize> = HashMap::new();
6769 let mut dependents: HashMap<InternedStr, Vec<InternedStr>> = HashMap::new();
6770
6771 for (name, _) in macros {
6772 in_degree.insert(**name, 0);
6773 }
6774
6775 for (name, info) in macros {
6776 for used in &info.uses {
6777 if macro_set.contains(used) {
6778 *in_degree.entry(**name).or_insert(0) += 1;
6780 dependents.entry(*used).or_default().push(**name);
6781 }
6782 }
6783 }
6784
6785 let mut queue: VecDeque<InternedStr> = {
6787 let mut zeros: Vec<_> = in_degree.iter()
6788 .filter(|(_, deg)| **deg == 0)
6789 .map(|(name, _)| *name)
6790 .collect();
6791 zeros.sort_by_key(|n| self.interner.get(*n));
6792 zeros.into_iter().collect()
6793 };
6794
6795 let mut result = Vec::with_capacity(macros.len());
6796
6797 while let Some(name) = queue.pop_front() {
6798 result.push(name);
6799 if let Some(deps) = dependents.get(&name) {
6800 let mut newly_ready: Vec<InternedStr> = Vec::new();
6802 for dep in deps {
6803 if let Some(deg) = in_degree.get_mut(dep) {
6804 *deg -= 1;
6805 if *deg == 0 {
6806 newly_ready.push(*dep);
6807 }
6808 }
6809 }
6810 newly_ready.sort_by_key(|n| self.interner.get(*n));
6812 for n in newly_ready {
6813 queue.push_back(n);
6814 }
6815 }
6816 }
6817
6818 if result.len() < macros.len() {
6820 let result_set: HashSet<_> = result.iter().copied().collect();
6821 let mut remaining: Vec<_> = macro_set.iter()
6822 .filter(|n| !result_set.contains(n))
6823 .copied()
6824 .collect();
6825 remaining.sort_by_key(|n| self.interner.get(*n));
6826 result.extend(remaining);
6827 }
6828
6829 result
6830 }
6831
6832 fn generate_macro_cascade_unavailable(
6834 &mut self,
6835 info: &MacroInferInfo,
6836 unavailable_deps: &[String],
6837 ) -> io::Result<()> {
6838 let name_str = self.interner.get(info.name);
6839 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6840 let mut deps: Vec<&String> = unavailable_deps.iter().collect();
6841 deps.sort(); let deps: Vec<&str> = deps.iter().map(|s| s.as_str()).collect();
6843 writeln!(self.writer,
6844 "// [CASCADE_UNAVAILABLE] {}{} - dependency not generated: {}",
6845 name_str, thx_info, deps.join(", "))?;
6846 writeln!(self.writer)?;
6847 Ok(())
6848 }
6849
6850 fn should_include_macro(&self, info: &MacroInferInfo) -> bool {
6852 if !info.is_target {
6854 return false;
6855 }
6856
6857 if !info.has_body {
6859 return false;
6860 }
6861
6862 info.is_function
6864 }
6865
6866 fn get_macro_status(&self, info: &MacroInferInfo) -> GenerateStatus {
6868 if info.calls_unavailable {
6870 return GenerateStatus::CallsUnavailable;
6871 }
6872
6873 if !info.generic_type_params.is_empty() {
6876 return GenerateStatus::GenericUnsupported;
6877 }
6878
6879 match &info.parse_result {
6880 ParseResult::Unparseable(_) => GenerateStatus::ParseFailed,
6881 ParseResult::Statement(items) => {
6882 if block_items_contain_goto(items) {
6884 return GenerateStatus::ContainsGoto;
6885 }
6886 if info.is_fully_confirmed() {
6887 GenerateStatus::Success
6888 } else {
6889 GenerateStatus::TypeIncomplete
6890 }
6891 }
6892 ParseResult::Expression(_) => {
6893 if info.is_fully_confirmed() {
6894 GenerateStatus::Success
6895 } else {
6896 GenerateStatus::TypeIncomplete
6897 }
6898 }
6899 }
6900 }
6901
6902 fn generate_macro_parse_failed(&mut self, info: &MacroInferInfo) -> io::Result<()> {
6904 let name_str = self.interner.get(info.name);
6905
6906 let params_str = if info.is_function {
6908 let params: Vec<_> = info.params.iter()
6909 .map(|p| self.interner.get(p.name).to_string())
6910 .collect();
6911 format!("({})", params.join(", "))
6912 } else {
6913 String::new()
6914 };
6915
6916 writeln!(self.writer, "// [PARSE_FAILED] {}{}", name_str, params_str)?;
6917
6918 if let ParseResult::Unparseable(Some(err_msg)) = &info.parse_result {
6920 writeln!(self.writer, "// Error: {}", err_msg)?;
6921 }
6922
6923 writeln!(self.writer, "// (tokens not available in parsed form)")?;
6925 writeln!(self.writer)?;
6926
6927 Ok(())
6928 }
6929
6930 fn generate_macro_calls_unavailable(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
6932 let name_str = self.interner.get(info.name);
6933
6934 let params_str = if info.is_function {
6936 let params: Vec<_> = info.params.iter()
6937 .map(|p| self.interner.get(p.name).to_string())
6938 .collect();
6939 format!("({})", params.join(", "))
6940 } else {
6941 String::new()
6942 };
6943
6944 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6946
6947 writeln!(self.writer, "// [CALLS_UNAVAILABLE] {}{}{} - calls unavailable function(s)", name_str, params_str, thx_info)?;
6948
6949 let unavailable_fns: Vec<_> = info.called_functions.iter()
6951 .filter(|&fn_id| {
6952 let fn_name = self.interner.get(*fn_id);
6953 !self.is_function_available(*fn_id, fn_name, result)
6955 })
6956 .map(|fn_id| self.interner.get(*fn_id))
6957 .collect();
6958
6959 if !unavailable_fns.is_empty() {
6960 let mut unavailable_fns = unavailable_fns;
6961 unavailable_fns.sort(); writeln!(self.writer, "// Unavailable: {}", unavailable_fns.join(", "))?;
6963 }
6964
6965 writeln!(self.writer)?;
6966
6967 Ok(())
6968 }
6969
6970 fn is_function_available(&self, fn_id: crate::InternedStr, fn_name: &str, result: &InferResult) -> bool {
6972 if result.infer_ctx.macros.contains_key(&fn_id) {
6974 return true;
6975 }
6976
6977 if let Some(rust_decl_dict) = &result.rust_decl_dict {
6979 if rust_decl_dict.fns.contains_key(fn_name) {
6980 return true;
6981 }
6982 }
6983
6984 if result.inline_fn_dict.get(fn_id).is_some() {
6986 return true;
6987 }
6988
6989 let builtin_fns = [
6991 "__builtin_expect",
6992 "__builtin_offsetof",
6993 "offsetof",
6994 "__builtin_types_compatible_p",
6995 "__builtin_constant_p",
6996 "__builtin_choose_expr",
6997 "__builtin_unreachable",
6998 "__builtin_trap",
6999 "__builtin_assume",
7000 "__builtin_bswap16",
7001 "__builtin_bswap32",
7002 "__builtin_bswap64",
7003 "__builtin_popcount",
7004 "__builtin_clz",
7005 "__builtin_ctz",
7006 "pthread_mutex_lock",
7007 "pthread_mutex_unlock",
7008 "pthread_rwlock_rdlock",
7009 "pthread_rwlock_wrlock",
7010 "pthread_rwlock_unlock",
7011 "memchr",
7012 "memcpy",
7013 "memmove",
7014 "memset",
7015 "strlen",
7016 "strcmp",
7017 "strncmp",
7018 "strcpy",
7019 "strncpy",
7020 "ASSERT_IS_LITERAL",
7021 "ASSERT_IS_PTR",
7022 "ASSERT_NOT_PTR",
7023 ];
7024
7025 if builtin_fns.contains(&fn_name) {
7026 return true;
7027 }
7028
7029 false
7030 }
7031
7032 fn generate_macro_type_incomplete(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7034 let name_str = self.interner.get(info.name);
7035
7036 let params_str = if info.is_function {
7038 let params: Vec<_> = info.params.iter()
7039 .map(|p| self.interner.get(p.name).to_string())
7040 .collect();
7041 format!("({})", params.join(", "))
7042 } else {
7043 String::new()
7044 };
7045
7046 writeln!(self.writer, "// [TYPE_INCOMPLETE] {}{}", name_str, params_str)?;
7047
7048 writeln!(self.writer, "// Args status: {:?}, Return status: {:?}",
7050 info.args_infer_status, info.return_infer_status)?;
7051
7052 writeln!(self.writer, "// Typed S-expression:")?;
7054 self.write_typed_sexp_comment(info, result)?;
7055
7056 writeln!(self.writer)?;
7057 Ok(())
7058 }
7059
7060 fn write_typed_sexp_comment(&mut self, info: &MacroInferInfo, _result: &InferResult) -> io::Result<()> {
7062 match &info.parse_result {
7063 ParseResult::Expression(expr) => {
7064 self.write_expr_sexp_comment(expr, info, "// ")?;
7065 }
7066 ParseResult::Statement(block_items) => {
7067 for item in block_items {
7068 if let BlockItem::Stmt(stmt) = item {
7069 self.write_stmt_sexp_comment(stmt, info, "// ")?;
7070 }
7071 }
7072 }
7073 ParseResult::Unparseable(_) => {
7074 writeln!(self.writer, "// (unparseable)")?;
7075 }
7076 }
7077 Ok(())
7078 }
7079
7080 fn write_expr_sexp_comment(&mut self, expr: &Expr, info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7082 let mut buf = Vec::new();
7084 {
7085 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7086 let _ = printer.print_expr(expr);
7087 }
7088
7089 let sexp_str = String::from_utf8_lossy(&buf);
7091 let type_info = self.get_expr_type_info(expr, info);
7092
7093 for line in sexp_str.lines() {
7095 writeln!(self.writer, "{}{}", prefix, line)?;
7096 }
7097 if !type_info.is_empty() {
7098 writeln!(self.writer, "{} :type {}", prefix, type_info)?;
7099 }
7100
7101 Ok(())
7102 }
7103
7104 fn write_stmt_sexp_comment(&mut self, stmt: &Stmt, _info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7106 let mut buf = Vec::new();
7107 {
7108 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7109 let _ = printer.print_stmt(stmt);
7110 }
7111
7112 let sexp_str = String::from_utf8_lossy(&buf);
7113 for line in sexp_str.lines() {
7114 writeln!(self.writer, "{}{}", prefix, line)?;
7115 }
7116
7117 Ok(())
7118 }
7119
7120 fn get_expr_type_info(&self, expr: &Expr, info: &MacroInferInfo) -> String {
7122 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
7124 if let Some(first) = constraints.first() {
7125 return first.ty.to_display_string(self.interner);
7126 }
7127 }
7128 "<unknown>".to_string()
7129 }
7130}