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 let mut all_expr_ids: Vec<crate::ast::ExprId> = info
491 .type_env
492 .param_to_exprs
493 .get(¶m.name)
494 .map(|ids| ids.iter().cloned().collect())
495 .unwrap_or_default();
496 all_expr_ids.push(param.expr_id());
497
498 for expr_id in &all_expr_ids {
499 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
500 for c in constraints {
501 if c.ty.is_void() { continue; }
502 let tier = c.ty.confidence_tier();
503 if best.is_none() || tier < best.unwrap().1 {
504 best = Some((&c.ty, tier));
505 }
506 }
507 }
508 }
509 best.map(|(t, _)| t.clone())
510}
511
512fn substitute_idents(expr: &mut Expr, subs: &HashMap<InternedStr, &Expr>) {
519 if let ExprKind::Ident(name) = &expr.kind {
520 if let Some(replacement) = subs.get(name) {
521 *expr = (*replacement).clone();
522 return;
523 }
524 }
525 match &mut expr.kind {
526 ExprKind::Ident(_)
527 | ExprKind::IntLit(_)
528 | ExprKind::UIntLit(_)
529 | ExprKind::FloatLit(_)
530 | ExprKind::CharLit(_)
531 | ExprKind::StringLit(_)
532 | ExprKind::SizeofType(_)
533 | ExprKind::Alignof(_) => {}
534 ExprKind::Index { expr: e, index } => {
535 substitute_idents(e, subs);
536 substitute_idents(index, subs);
537 }
538 ExprKind::Call { func, args } => {
539 substitute_idents(func, subs);
540 for arg in args {
541 substitute_idents(arg, subs);
542 }
543 }
544 ExprKind::Member { expr: e, .. }
545 | ExprKind::PtrMember { expr: e, .. }
546 | ExprKind::PostInc(e)
547 | ExprKind::PostDec(e)
548 | ExprKind::PreInc(e)
549 | ExprKind::PreDec(e)
550 | ExprKind::AddrOf(e)
551 | ExprKind::Deref(e)
552 | ExprKind::UnaryPlus(e)
553 | ExprKind::UnaryMinus(e)
554 | ExprKind::BitNot(e)
555 | ExprKind::LogNot(e)
556 | ExprKind::Sizeof(e)
557 | ExprKind::Cast { expr: e, .. } => substitute_idents(e, subs),
558 ExprKind::Binary { lhs, rhs, .. }
559 | ExprKind::Assign { lhs, rhs, .. }
560 | ExprKind::Comma { lhs, rhs } => {
561 substitute_idents(lhs, subs);
562 substitute_idents(rhs, subs);
563 }
564 ExprKind::Conditional { cond, then_expr, else_expr } => {
565 substitute_idents(cond, subs);
566 substitute_idents(then_expr, subs);
567 substitute_idents(else_expr, subs);
568 }
569 ExprKind::Assert { condition, .. } => substitute_idents(condition, subs),
570 ExprKind::MacroCall { args, expanded, .. } => {
571 for arg in args {
572 substitute_idents(arg, subs);
573 }
574 substitute_idents(expanded, subs);
575 }
576 ExprKind::BuiltinCall { args, .. } => {
577 for arg in args {
578 if let crate::ast::BuiltinArg::Expr(e) = arg {
579 substitute_idents(e, subs);
580 }
581 }
582 }
583 ExprKind::CompoundLit { init, .. } => {
584 for item in init {
585 if let crate::ast::Initializer::Expr(e) = &mut item.init {
586 substitute_idents(e, subs);
587 }
588 }
589 }
590 ExprKind::StmtExpr(_) => {}
592 }
593}
594
595fn expr_yields_value_for_stmt_use(expr: &syn::Expr) -> bool {
609 match expr {
610 syn::Expr::Block(b) => {
611 matches!(b.block.stmts.last(), Some(syn::Stmt::Expr(_, None)))
612 }
613 syn::Expr::Binary(b) => matches!(
614 b.op,
615 syn::BinOp::And(_) | syn::BinOp::Or(_)
616 ),
617 syn::Expr::Unary(_) => true,
618 syn::Expr::Paren(p) => expr_yields_value_for_stmt_use(&p.expr),
620 _ => false,
621 }
622}
623
624fn is_unsigned_cast_expr(expr_str: &str) -> bool {
627 if let Some(pos) = expr_str.rfind(" as ") {
628 let after = &expr_str[pos + 4..].trim_end_matches(')');
629 matches!(*after, "usize" | "u8" | "u16" | "u32" | "u64" | "u128" | "c_uint" | "c_ulong" | "c_ulonglong")
630 } else {
631 false
632 }
633}
634
635fn is_unsigned_integer_target(ty: &str) -> bool {
638 matches!(ty,
639 "u8" | "u16" | "u32" | "u64" | "u128" | "usize" |
640 "U8" | "U16" | "U32" | "U64" |
641 "UV" | "STRLEN" | "Size_t" | "size_t" | "PERL_UINTMAX_T" |
642 "c_uchar" | "c_ushort" | "c_uint" | "c_ulong" | "c_ulonglong"
643 )
644}
645
646
647fn strip_outer_parens(s: &str) -> &str {
651 let s = s.trim();
652 if s.len() < 2 || !s.starts_with('(') || !s.ends_with(')') {
653 return s;
654 }
655 let inner = &s[1..s.len() - 1];
657 if inner.trim_start().starts_with('{') {
659 return s;
660 }
661 let mut depth = 0i32;
662 for ch in inner.chars() {
663 match ch {
664 '(' | '{' | '[' => depth += 1,
665 ')' | '}' | ']' => {
666 depth -= 1;
667 if depth < 0 {
668 return s;
670 }
671 }
672 _ => {}
673 }
674 }
675 if depth == 0 {
676 inner
677 } else {
678 s
679 }
680}
681
682fn extract_assert_message(expr: &Expr) -> Option<String> {
685 if let ExprKind::LogNot(inner) = &expr.kind {
686 if let ExprKind::StringLit(bytes) = &inner.kind {
687 return Some(String::from_utf8_lossy(bytes).into_owned());
688 }
689 }
690 None
691}
692
693fn decompose_assert_with_message(condition: &Expr) -> Option<(&Expr, String)> {
695 if let ExprKind::Binary { op: BinOp::LogOr, lhs, rhs } = &condition.kind {
696 if let Some(msg) = extract_assert_message(rhs) {
697 return Some((lhs, msg));
698 }
699 }
700 None
701}
702
703fn is_sv_subtype_cast(from: &UnifiedType, to: &UnifiedType) -> bool {
705 let inner_name = |ut: &UnifiedType| -> Option<String> {
708 match ut.inner_type()? {
709 UnifiedType::Named(name) => Some(name.clone()),
710 UnifiedType::Void => Some("c_void".to_string()),
711 _ => None,
712 }
713 };
714 let from_name = match inner_name(from) {
715 Some(n) => n,
716 None => return false,
717 };
718 let to_name = match inner_name(to) {
719 Some(n) => n,
720 None => return false,
721 };
722 const SV_SUBTYPES: &[&str] = &[
726 "GV", "HV", "AV", "CV", "IO", "p5rx", "REGEXP",
727 "gv", "hv", "av", "cv", "io", "regexp",
728 ];
729 let sv_like = |n: &str| n == "SV" || n == "sv";
730 (SV_SUBTYPES.contains(&from_name.as_str()) && sv_like(&to_name))
732 || (sv_like(&from_name) && SV_SUBTYPES.contains(&to_name.as_str()))
733 || (SV_SUBTYPES.contains(&from_name.as_str())
735 && SV_SUBTYPES.contains(&to_name.as_str()))
736 || to_name == "c_void"
738 || from_name == "c_void"
739}
740
741fn is_null_literal(expr: &Expr) -> bool {
742 match &expr.kind {
743 ExprKind::IntLit(0) => true,
744 ExprKind::Cast { expr: inner, .. } => is_null_literal(inner),
745 _ => false,
746 }
747}
748
749fn null_ptr_expr(return_type: &UnifiedType) -> String {
751 if return_type.is_const_pointer() {
752 "std::ptr::null()".to_string()
753 } else {
754 "std::ptr::null_mut()".to_string()
755 }
756}
757
758fn normalize_integer_type(ty: &str) -> Option<&'static str> {
760 match ty {
761 "u8" | "U8" | "c_uchar" => Some("u8"),
762 "u16" | "U16" | "c_ushort" => Some("u16"),
763 "u32" | "U32" | "c_uint" => Some("u32"),
764 "u64" | "U64" | "UV" | "c_ulong" | "c_ulonglong"
765 | "PERL_UINTMAX_T" => Some("u64"),
766 "i8" | "I8" | "c_schar" | "c_char" => Some("i8"),
767 "i16" | "I16" | "c_short" => Some("i16"),
768 "i32" | "I32" | "c_int" => Some("i32"),
769 "i64" | "I64" | "IV" | "c_long" | "c_longlong" => Some("i64"),
770 "usize" | "STRLEN" => Some("usize"),
771 "isize" | "SSize_t" | "ssize_t" | "PADOFFSET" => Some("isize"),
772 "Stack_off_t" => Some("i32"),
775 _ => None,
776 }
777}
778
779fn integer_types_compatible(a: &str, b: &str) -> bool {
781 if a == b { return true; }
782 matches!((a, b),
783 ("i64", "isize") | ("isize", "i64") |
784 ("u64", "usize") | ("usize", "u64")
785 )
786}
787
788fn integer_type_rank(ty: &str) -> Option<(bool, u8)> {
791 match normalize_integer_type(ty)? {
792 "u8" => Some((false, 1)), "i8" => Some((true, 1)),
793 "u16" => Some((false, 2)), "i16" => Some((true, 2)),
794 "u32" => Some((false, 4)), "i32" => Some((true, 4)),
795 "u64" => Some((false, 8)), "i64" => Some((true, 8)),
796 "usize" => Some((false, 8)), "isize" => Some((true, 8)),
797 _ => None,
798 }
799}
800
801fn wider_integer_type(a: &str, b: &str) -> Option<&'static str> {
804 let na = normalize_integer_type(a)?;
805 let nb = normalize_integer_type(b)?;
806 if na == nb { return None; }
807 let (a_signed, a_rank) = integer_type_rank(a)?;
808 let (_b_signed, b_rank) = integer_type_rank(b)?;
809 if a_rank == b_rank {
810 Some(if a_signed { nb } else { na })
812 } else if a_rank > b_rank {
813 Some(na)
814 } else {
815 Some(nb)
816 }
817}
818
819pub fn pointer_inner_compatible(a: &UnifiedType, b: &UnifiedType) -> bool {
826 let a_inner = match a { UnifiedType::Pointer { inner, .. } => inner.as_ref(), _ => return false };
827 let b_inner = match b { UnifiedType::Pointer { inner, .. } => inner.as_ref(), _ => return false };
828 type_inner_compatible(a_inner, b_inner)
829}
830
831fn type_inner_compatible(a: &UnifiedType, b: &UnifiedType) -> bool {
833 if a.is_pointer() && b.is_pointer() {
835 return pointer_inner_compatible(a, b);
836 }
837 let a_s = a.to_rust_string();
839 let b_s = b.to_rust_string();
840 if let (Some(na), Some(nb)) = (normalize_integer_type(&a_s), normalize_integer_type(&b_s)) {
841 return na == nb;
842 }
843 if a.is_void() && b.is_void() { return true; }
845 a_s == b_s
847}
848
849pub fn pointer_const_differs(a: &UnifiedType, b: &UnifiedType) -> bool {
851 if !(a.is_pointer() && b.is_pointer()) { return false; }
852 if a.is_const_pointer() == b.is_const_pointer() { return false; }
853 pointer_inner_compatible(a, b)
854}
855
856pub fn collect_must_mut_pointer_params(
861 parse_result: &ParseResult,
862 params: &[MacroParam],
863 callee_const_params: &HashMap<InternedStr, HashSet<usize>>,
864) -> HashSet<InternedStr> {
865 let param_names: HashSet<InternedStr> = params.iter().map(|p| p.name).collect();
866 let mut result = HashSet::new();
867 match parse_result {
868 ParseResult::Expression(expr) => {
869 collect_must_mut_from_expr(expr, ¶m_names, callee_const_params, &mut result);
870 }
871 ParseResult::Statement(items) => {
872 for item in items {
873 if let BlockItem::Stmt(stmt) = item {
874 collect_must_mut_from_stmt(stmt, ¶m_names, callee_const_params, &mut result);
875 }
876 }
877 }
878 ParseResult::Unparseable(_) => {}
879 }
880 result
881}
882
883pub fn collect_must_mut_from_stmt(
884 stmt: &Stmt,
885 params: &HashSet<InternedStr>,
886 callee_const: &HashMap<InternedStr, HashSet<usize>>,
887 result: &mut HashSet<InternedStr>,
888) {
889 match stmt {
890 Stmt::Expr(Some(expr), _) | Stmt::Return(Some(expr), _) => {
891 collect_must_mut_from_expr(expr, params, callee_const, result);
892 }
893 Stmt::Compound(compound) => {
894 for item in &compound.items {
895 match item {
896 BlockItem::Stmt(s) => collect_must_mut_from_stmt(s, params, callee_const, result),
897 BlockItem::Decl(decl) => {
898 for init_decl in &decl.declarators {
899 if let Some(Initializer::Expr(init)) = &init_decl.init {
900 collect_must_mut_from_expr(init, params, callee_const, result);
901 }
902 }
903 }
904 }
905 }
906 }
907 Stmt::If { cond, then_stmt, else_stmt, .. } => {
908 collect_must_mut_from_expr(cond, params, callee_const, result);
909 collect_must_mut_from_stmt(then_stmt, params, callee_const, result);
910 if let Some(e) = else_stmt {
911 collect_must_mut_from_stmt(e, params, callee_const, result);
912 }
913 }
914 Stmt::While { cond, body, .. } | Stmt::DoWhile { cond, body, .. } => {
915 collect_must_mut_from_expr(cond, params, callee_const, result);
916 collect_must_mut_from_stmt(body, params, callee_const, result);
917 }
918 Stmt::For { init, cond, step, body, .. } => {
919 if let Some(ForInit::Expr(e)) = init { collect_must_mut_from_expr(e, params, callee_const, result); }
920 if let Some(e) = cond { collect_must_mut_from_expr(e, params, callee_const, result); }
921 if let Some(e) = step { collect_must_mut_from_expr(e, params, callee_const, result); }
922 collect_must_mut_from_stmt(body, params, callee_const, result);
923 }
924 Stmt::Switch { expr, body, .. } => {
925 collect_must_mut_from_expr(expr, params, callee_const, result);
926 collect_must_mut_from_stmt(body, params, callee_const, result);
927 }
928 _ => {}
929 }
930}
931
932pub fn collect_must_mut_from_expr(
933 expr: &Expr,
934 params: &HashSet<InternedStr>,
935 callee_const: &HashMap<InternedStr, HashSet<usize>>,
936 result: &mut HashSet<InternedStr>,
937) {
938 match &expr.kind {
939 ExprKind::Assign { lhs, rhs, .. } => {
941 mark_lvalue_mut(lhs, params, result);
942 collect_must_mut_from_expr(lhs, params, callee_const, result);
943 collect_must_mut_from_expr(rhs, params, callee_const, result);
944 }
945 ExprKind::PreInc(inner) | ExprKind::PreDec(inner) |
947 ExprKind::PostInc(inner) | ExprKind::PostDec(inner) => {
948 mark_lvalue_mut(inner, params, result);
949 collect_must_mut_from_expr(inner, params, callee_const, result);
950 }
951 ExprKind::Call { func, args } => {
953 if let ExprKind::Ident(func_name) = &func.kind {
955 let const_arg_positions = callee_const.get(func_name);
956 for (i, arg) in args.iter().enumerate() {
957 if let ExprKind::Ident(arg_name) = &arg.kind {
958 if params.contains(arg_name) {
959 let is_const_at_callee = const_arg_positions
961 .map_or(false, |positions| positions.contains(&i));
962 if !is_const_at_callee {
963 result.insert(*arg_name);
965 }
966 }
967 }
968 collect_must_mut_from_expr(arg, params, callee_const, result);
969 }
970 } else {
971 for arg in args {
972 collect_must_mut_from_expr(arg, params, callee_const, result);
973 }
974 }
975 collect_must_mut_from_expr(func, params, callee_const, result);
976 }
977 ExprKind::Binary { lhs, rhs, .. } | ExprKind::Comma { lhs, rhs } => {
979 collect_must_mut_from_expr(lhs, params, callee_const, result);
980 collect_must_mut_from_expr(rhs, params, callee_const, result);
981 }
982 ExprKind::Conditional { cond, then_expr, else_expr } => {
983 collect_must_mut_from_expr(cond, params, callee_const, result);
984 collect_must_mut_from_expr(then_expr, params, callee_const, result);
985 collect_must_mut_from_expr(else_expr, params, callee_const, result);
986 }
987 ExprKind::MacroCall { name, args, expanded, .. } => {
989 let const_arg_positions = callee_const.get(name);
990 for (i, arg) in args.iter().enumerate() {
991 if let ExprKind::Ident(arg_name) = &arg.kind {
992 if params.contains(arg_name) {
993 let is_const_at_callee = const_arg_positions
994 .map_or(false, |positions| positions.contains(&i));
995 if !is_const_at_callee {
996 result.insert(*arg_name);
997 }
998 }
999 }
1000 collect_must_mut_from_expr(arg, params, callee_const, result);
1001 }
1002 collect_must_mut_from_expr(expanded, params, callee_const, result);
1003 }
1004 ExprKind::Deref(inner) | ExprKind::UnaryMinus(inner) | ExprKind::BitNot(inner) |
1005 ExprKind::LogNot(inner) | ExprKind::AddrOf(inner) |
1006 ExprKind::Cast { expr: inner, .. } => {
1007 collect_must_mut_from_expr(inner, params, callee_const, result);
1008 }
1009 ExprKind::Member { expr: inner, .. } | ExprKind::PtrMember { expr: inner, .. } => {
1010 collect_must_mut_from_expr(inner, params, callee_const, result);
1011 }
1012 ExprKind::Sizeof(inner) => {
1013 collect_must_mut_from_expr(inner, params, callee_const, result);
1014 }
1015 ExprKind::Assert { condition, .. } => {
1016 collect_must_mut_from_expr(condition, params, callee_const, result);
1017 }
1018 ExprKind::StmtExpr(compound) => {
1019 for item in &compound.items {
1020 match item {
1021 BlockItem::Stmt(s) => collect_must_mut_from_stmt(s, params, callee_const, result),
1022 BlockItem::Decl(decl) => {
1023 for init_decl in &decl.declarators {
1024 if let Some(Initializer::Expr(init)) = &init_decl.init {
1025 collect_must_mut_from_expr(init, params, callee_const, result);
1026 }
1027 }
1028 }
1029 }
1030 }
1031 }
1032 _ => {}
1033 }
1034}
1035
1036pub fn mark_lvalue_mut(expr: &Expr, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1038 match &expr.kind {
1039 ExprKind::Deref(inner) => {
1041 if let ExprKind::Ident(name) = &inner.kind {
1042 if params.contains(name) {
1043 result.insert(*name);
1044 }
1045 }
1046 mark_lvalue_mut(inner, params, result);
1048 }
1049 ExprKind::PtrMember { expr: inner, .. } => {
1051 if let ExprKind::Ident(name) = &inner.kind {
1052 if params.contains(name) {
1053 result.insert(*name);
1054 }
1055 }
1056 mark_lvalue_mut(inner, params, result);
1057 }
1058 ExprKind::Member { expr: inner, .. } => {
1060 mark_lvalue_mut(inner, params, result);
1061 }
1062 ExprKind::Cast { expr: inner, type_name } => {
1064 if let ExprKind::Ident(name) = &inner.kind {
1065 if params.contains(name) {
1066 let has_non_const_ptr = type_name.declarator.as_ref()
1068 .map(|d| d.derived.iter().any(|dd| {
1069 matches!(dd, crate::ast::DerivedDecl::Pointer(q) if !q.is_const)
1070 }))
1071 .unwrap_or(false);
1072 if has_non_const_ptr {
1073 result.insert(*name);
1074 }
1075 }
1076 }
1077 mark_lvalue_mut(inner, params, result);
1078 }
1079 ExprKind::MacroCall { expanded, args, .. } => {
1081 mark_lvalue_mut(expanded, params, result);
1082 for arg in args {
1084 mark_lvalue_mut(arg, params, result);
1085 }
1086 }
1087 ExprKind::Call { args, .. } => {
1090 for arg in args {
1091 if let ExprKind::Ident(name) = &arg.kind {
1092 if params.contains(name) {
1093 result.insert(*name);
1094 }
1095 }
1096 mark_lvalue_mut(arg, params, result);
1097 }
1098 }
1099 _ => {}
1100 }
1101}
1102
1103fn collect_mut_params(parse_result: &ParseResult, params: &[MacroParam]) -> HashSet<InternedStr> {
1104 let param_names: HashSet<InternedStr> = params.iter().map(|p| p.name).collect();
1105 let mut result = HashSet::new();
1106 match parse_result {
1107 ParseResult::Expression(expr) => collect_mut_params_from_expr(expr, ¶m_names, &mut result),
1108 ParseResult::Statement(items) => {
1109 for item in items {
1110 if let BlockItem::Stmt(stmt) = item {
1111 collect_mut_params_from_stmt(stmt, ¶m_names, &mut result);
1112 }
1113 }
1114 }
1115 ParseResult::Unparseable(_) => {}
1116 }
1117 result
1118}
1119
1120fn collect_mut_params_from_expr(expr: &Expr, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1121 match &expr.kind {
1122 ExprKind::AddrOf(inner) => {
1123 if let ExprKind::Ident(name) = &inner.kind {
1125 if params.contains(name) {
1126 result.insert(*name);
1127 }
1128 }
1129 collect_mut_params_from_expr(inner, params, result);
1130 }
1131 ExprKind::Assign { lhs, rhs, .. } => {
1132 if let ExprKind::Ident(name) = &lhs.kind {
1134 if params.contains(name) {
1135 result.insert(*name);
1136 }
1137 }
1138 collect_mut_params_from_expr(lhs, params, result);
1139 collect_mut_params_from_expr(rhs, params, result);
1140 }
1141 ExprKind::PreInc(inner) | ExprKind::PreDec(inner) |
1142 ExprKind::PostInc(inner) | ExprKind::PostDec(inner) => {
1143 if let ExprKind::Ident(name) = &inner.kind {
1144 if params.contains(name) {
1145 result.insert(*name);
1146 }
1147 }
1148 collect_mut_params_from_expr(inner, params, result);
1149 }
1150 ExprKind::Binary { lhs, rhs, .. } => {
1152 collect_mut_params_from_expr(lhs, params, result);
1153 collect_mut_params_from_expr(rhs, params, result);
1154 }
1155 ExprKind::Deref(inner) | ExprKind::UnaryMinus(inner) | ExprKind::BitNot(inner) |
1156 ExprKind::LogNot(inner) | ExprKind::Cast { expr: inner, .. } => {
1157 collect_mut_params_from_expr(inner, params, result);
1158 }
1159 ExprKind::Call { func, args } => {
1160 collect_mut_params_from_expr(func, params, result);
1161 for arg in args {
1162 collect_mut_params_from_expr(arg, params, result);
1163 }
1164 }
1165 ExprKind::MacroCall { expanded, args, .. } => {
1166 collect_mut_params_from_expr(expanded, params, result);
1167 for arg in args {
1168 collect_mut_params_from_expr(arg, params, result);
1169 }
1170 }
1171 ExprKind::Conditional { cond, then_expr, else_expr } => {
1172 collect_mut_params_from_expr(cond, params, result);
1173 collect_mut_params_from_expr(then_expr, params, result);
1174 collect_mut_params_from_expr(else_expr, params, result);
1175 }
1176 ExprKind::Comma { lhs, rhs } => {
1177 collect_mut_params_from_expr(lhs, params, result);
1178 collect_mut_params_from_expr(rhs, params, result);
1179 }
1180 ExprKind::Member { expr: inner, .. } | ExprKind::PtrMember { expr: inner, .. } => {
1181 collect_mut_params_from_expr(inner, params, result);
1182 }
1183 ExprKind::StmtExpr(compound) => {
1184 for item in &compound.items {
1185 if let BlockItem::Stmt(stmt) = item {
1186 collect_mut_params_from_stmt(stmt, params, result);
1187 }
1188 }
1189 }
1190 _ => {}
1191 }
1192}
1193
1194fn collect_mut_params_from_stmt(stmt: &Stmt, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1195 match stmt {
1196 Stmt::Expr(Some(expr), _) => collect_mut_params_from_expr(expr, params, result),
1197 Stmt::Return(Some(expr), _) => collect_mut_params_from_expr(expr, params, result),
1198 Stmt::If { cond, then_stmt, else_stmt, .. } => {
1199 collect_mut_params_from_expr(cond, params, result);
1200 collect_mut_params_from_stmt(then_stmt, params, result);
1201 if let Some(else_s) = else_stmt {
1202 collect_mut_params_from_stmt(else_s, params, result);
1203 }
1204 }
1205 Stmt::Compound(compound) => {
1206 for item in &compound.items {
1207 if let BlockItem::Stmt(s) = item {
1208 collect_mut_params_from_stmt(s, params, result);
1209 }
1210 }
1211 }
1212 Stmt::While { cond, body, .. } | Stmt::DoWhile { body, cond, .. } => {
1213 collect_mut_params_from_expr(cond, params, result);
1214 collect_mut_params_from_stmt(body, params, result);
1215 }
1216 Stmt::For { init, cond, step, body, .. } => {
1217 if let Some(ForInit::Expr(e)) = init {
1218 collect_mut_params_from_expr(e, params, result);
1219 }
1220 if let Some(c) = cond {
1221 collect_mut_params_from_expr(c, params, result);
1222 }
1223 if let Some(s) = step {
1224 collect_mut_params_from_expr(s, params, result);
1225 }
1226 collect_mut_params_from_stmt(body, params, result);
1227 }
1228 _ => {}
1229 }
1230}
1231
1232fn type_str_is_fn_pointer(ty_str: &str) -> bool {
1239 ty_str.contains("fn(") || ty_str.contains("fn (")
1240}
1241
1242fn build_field_type_map(dict: Option<&RustDeclDict>) -> HashMap<String, UnifiedType> {
1243 let mut map: HashMap<String, UnifiedType> = HashMap::new();
1244 let mut conflicts: HashSet<String> = HashSet::new();
1245 if let Some(dict) = dict {
1246 for st in dict.structs.values() {
1247 for field in &st.fields {
1248 if conflicts.contains(&field.name) {
1249 continue;
1250 }
1251 match map.entry(field.name.clone()) {
1252 std::collections::hash_map::Entry::Vacant(e) => {
1253 e.insert(field.uty.clone());
1254 }
1255 std::collections::hash_map::Entry::Occupied(e) => {
1256 if e.get() != &field.uty {
1257 conflicts.insert(field.name.clone());
1258 e.remove();
1259 }
1260 }
1261 }
1262 }
1263 }
1264 for ((_struct, method), ret_ty) in &dict.bitfield_method_types {
1269 if conflicts.contains(method) {
1270 continue;
1271 }
1272 let uty = UnifiedType::from_rust_str(ret_ty);
1273 match map.entry(method.clone()) {
1274 std::collections::hash_map::Entry::Vacant(e) => {
1275 e.insert(uty);
1276 }
1277 std::collections::hash_map::Entry::Occupied(e) => {
1278 if e.get() != &uty {
1279 conflicts.insert(method.clone());
1280 e.remove();
1281 }
1282 }
1283 }
1284 }
1285 }
1286 map
1287}
1288
1289#[derive(Debug, Clone)]
1291pub struct CodegenConfig {
1292 pub emit_inline_fns: bool,
1294 pub emit_macros: bool,
1296 pub include_source_location: bool,
1298 pub use_statements: Vec<String>,
1301 pub dump_ast_for: Option<String>,
1303 pub dump_types_for: Option<String>,
1305}
1306
1307impl Default for CodegenConfig {
1308 fn default() -> Self {
1309 Self {
1310 emit_inline_fns: true,
1311 emit_macros: true,
1312 include_source_location: true,
1313 use_statements: Vec::new(),
1314 dump_ast_for: None,
1315 dump_types_for: None,
1316 }
1317 }
1318}
1319
1320impl CodegenConfig {
1321 pub fn default_use_statements() -> Vec<String> {
1326 vec![
1327 "#[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(),
1330 "#[allow(non_camel_case_types, dead_code)] type size_t = usize".to_string(),
1331 "#[allow(non_camel_case_types, dead_code)] type ssize_t = isize".to_string(),
1332 "#[allow(non_camel_case_types, dead_code)] type SSize_t = isize".to_string(),
1333 ]
1334 }
1335
1336 pub fn with_use_statements(mut self, statements: Vec<String>) -> Self {
1338 self.use_statements = statements;
1339 self
1340 }
1341
1342 pub fn add_use_statement(mut self, statement: impl Into<String>) -> Self {
1344 self.use_statements.push(statement.into());
1345 self
1346 }
1347}
1348
1349#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1351pub enum GenerateStatus {
1352 Success,
1354 ParseFailed,
1356 TypeIncomplete,
1358 CallsUnavailable,
1360 ContainsGoto,
1362 GenericUnsupported,
1364 Skip,
1366}
1367
1368fn stmt_contains_goto(stmt: &Stmt) -> bool {
1370 match stmt {
1371 Stmt::Goto(_, _) => true,
1372 Stmt::Compound(cs) => block_items_contain_goto(&cs.items),
1373 Stmt::If { then_stmt, else_stmt, .. } => {
1374 stmt_contains_goto(then_stmt)
1375 || else_stmt.as_ref().is_some_and(|s| stmt_contains_goto(s))
1376 }
1377 Stmt::Switch { body, .. }
1378 | Stmt::While { body, .. }
1379 | Stmt::For { body, .. } => stmt_contains_goto(body),
1380 Stmt::DoWhile { body, .. } => stmt_contains_goto(body),
1381 Stmt::Label { stmt, .. } => stmt_contains_goto(stmt),
1382 Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => stmt_contains_goto(stmt),
1383 _ => false,
1384 }
1385}
1386
1387fn block_items_contain_goto(items: &[BlockItem]) -> bool {
1389 items.iter().any(|item| match item {
1390 BlockItem::Stmt(stmt) => stmt_contains_goto(stmt),
1391 BlockItem::Decl(_) => false,
1392 })
1393}
1394
1395fn stmt_contains_top_level_break(stmt: &Stmt) -> bool {
1398 match stmt {
1399 Stmt::Break(_) => true,
1400 Stmt::Compound(cs) => cs.items.iter().any(|item| match item {
1401 BlockItem::Stmt(s) => stmt_contains_top_level_break(s),
1402 BlockItem::Decl(_) => false,
1403 }),
1404 Stmt::If { then_stmt, else_stmt, .. } => {
1405 stmt_contains_top_level_break(then_stmt)
1406 || else_stmt.as_ref().is_some_and(|s| stmt_contains_top_level_break(s))
1407 }
1408 Stmt::Label { stmt, .. } => stmt_contains_top_level_break(stmt),
1409 _ => false,
1412 }
1413}
1414
1415#[derive(Debug, Clone, Default)]
1417pub struct CodegenStats {
1418 pub macros_success: usize,
1420 pub macros_parse_failed: usize,
1422 pub macros_type_incomplete: usize,
1424 pub macros_calls_unavailable: usize,
1426 pub macros_cascade_unavailable: usize,
1428 pub macros_generic_unsupported: usize,
1430 pub macros_unresolved_names: usize,
1432 pub inline_fns_success: usize,
1434 pub inline_fns_type_incomplete: usize,
1436 pub inline_fns_unresolved_names: usize,
1438 pub inline_fns_cascade_unavailable: usize,
1440 pub inline_fns_contains_goto: usize,
1442}
1443
1444#[derive(Debug, Clone)]
1446pub struct GeneratedCode {
1447 pub code: String,
1449 pub incomplete_count: usize,
1451 pub unresolved_names: Vec<String>,
1453 pub used_libc_fns: HashSet<String>,
1455 pub codegen_errors: Vec<String>,
1457}
1458
1459impl GeneratedCode {
1460 pub fn is_complete(&self) -> bool {
1462 self.incomplete_count == 0
1463 }
1464
1465 pub fn has_unresolved_names(&self) -> bool {
1467 !self.unresolved_names.is_empty()
1468 }
1469}
1470
1471pub struct RustCodegen<'a> {
1477 interner: &'a StringInterner,
1478 enum_dict: &'a EnumDict,
1480 macro_ctx: &'a MacroInferContext,
1482 bindings_info: BindingsInfo,
1484 buffer: String,
1486 incomplete_count: usize,
1488 current_type_param_map: HashMap<InternedStr, String>,
1491 current_literal_string_params: HashSet<InternedStr>,
1493 current_return_type: Option<UnifiedType>,
1495 param_substitutions: HashMap<InternedStr, String>,
1498 current_param_types: HashMap<InternedStr, UnifiedType>,
1501 known_symbols: &'a KnownSymbols,
1503 current_local_names: HashSet<InternedStr>,
1505 unresolved_names: Vec<String>,
1507 used_libc_fns: HashSet<String>,
1509 rust_decl_dict: Option<&'a RustDeclDict>,
1511 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1513 fields_dict: Option<&'a crate::fields_dict::FieldsDict>,
1515 field_type_map: HashMap<String, UnifiedType>,
1517 dump_ast_for: Option<String>,
1519 dump_types_for: Option<String>,
1521 const_pointer_positions: HashSet<usize>,
1523 mut_local_names: HashSet<InternedStr>,
1525 codegen_errors: Vec<String>,
1527 is_bool_return: bool,
1529 bool_return_macros: HashSet<InternedStr>,
1531 perl_threaded: bool,
1533}
1534
1535pub struct CodegenDriver<'a, W: Write> {
1540 writer: W,
1541 interner: &'a StringInterner,
1542 enum_dict: &'a EnumDict,
1544 macro_ctx: &'a MacroInferContext,
1546 bindings_info: BindingsInfo,
1548 config: CodegenConfig,
1549 stats: CodegenStats,
1550 used_libc_fns: HashSet<String>,
1552 successfully_generated_inlines: HashSet<InternedStr>,
1554 generatable_macros: HashSet<InternedStr>,
1556 const_pointer_params: HashMap<InternedStr, HashSet<usize>>,
1558 bool_return_macros: HashSet<InternedStr>,
1560 perl_threaded: bool,
1562}
1563
1564impl<'a> RustCodegen<'a> {
1565 pub fn new(
1567 interner: &'a StringInterner,
1568 enum_dict: &'a EnumDict,
1569 macro_ctx: &'a MacroInferContext,
1570 bindings_info: BindingsInfo,
1571 known_symbols: &'a KnownSymbols,
1572 rust_decl_dict: Option<&'a RustDeclDict>,
1573 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1574 ) -> Self {
1575 Self {
1576 interner,
1577 enum_dict,
1578 macro_ctx,
1579 bindings_info,
1580 buffer: String::new(),
1581 incomplete_count: 0,
1582 current_type_param_map: HashMap::new(),
1583 current_literal_string_params: HashSet::new(),
1584 current_return_type: None,
1585 param_substitutions: HashMap::new(),
1586 current_param_types: HashMap::new(),
1587 known_symbols,
1588 current_local_names: HashSet::new(),
1589 unresolved_names: Vec::new(),
1590 used_libc_fns: HashSet::new(),
1591 rust_decl_dict,
1592 inline_fn_dict,
1593 fields_dict: None,
1594 field_type_map: build_field_type_map(rust_decl_dict),
1595 dump_ast_for: None,
1596 dump_types_for: None,
1597 const_pointer_positions: HashSet::new(),
1598 is_bool_return: false,
1599 bool_return_macros: HashSet::new(),
1600 mut_local_names: HashSet::new(),
1601 codegen_errors: Vec::new(),
1602 perl_threaded: true,
1605 }
1606 }
1607
1608 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
1610 self.perl_threaded = threaded;
1611 self
1612 }
1613
1614 pub fn with_dump_ast_for(mut self, name: Option<String>) -> Self {
1616 self.dump_ast_for = name;
1617 self
1618 }
1619
1620 pub fn with_dump_types_for(mut self, name: Option<String>) -> Self {
1621 self.dump_types_for = name;
1622 self
1623 }
1624
1625 pub fn with_fields_dict(mut self, dict: &'a crate::fields_dict::FieldsDict) -> Self {
1627 self.fields_dict = Some(dict);
1628 for (_name, def) in dict.iter_struct_defs() {
1633 for m in &def.members {
1634 let member_name = self.interner.get(m.name).to_string();
1635 if self.field_type_map.contains_key(&member_name) {
1636 continue;
1637 }
1638 let rust_ty = m.type_repr.to_rust_string(self.interner);
1639 self.field_type_map
1640 .insert(member_name, UnifiedType::from_rust_str(&rust_ty));
1641 }
1642 }
1643 self
1644 }
1645
1646 pub fn with_const_pointer_positions(mut self, positions: HashSet<usize>) -> Self {
1648 self.const_pointer_positions = positions;
1649 self
1650 }
1651
1652 pub fn with_bool_return(mut self, is_bool: bool, bool_macros: HashSet<InternedStr>) -> Self {
1654 self.is_bool_return = is_bool;
1655 self.bool_return_macros = bool_macros;
1656 self
1657 }
1658
1659 fn dump_type_info(&self, name_str: &str, info: &MacroInferInfo, params_str: &str, return_type: &str) {
1662 eprintln!("=== Type dump for {} ===", name_str);
1663 for (i, p) in info.params.iter().enumerate() {
1665 let pname = self.interner.get(p.name);
1666 let is_const = info.const_pointer_positions.contains(&i);
1667 let expr_ids: Vec<_> = info.type_env.param_to_exprs
1669 .get(&p.name)
1670 .map(|ids| ids.iter().cloned().collect())
1671 .unwrap_or_default();
1672 let mut all_ids = expr_ids;
1673 all_ids.push(p.expr_id());
1674 eprintln!(" param[{}] {} (const_position={})", i, pname, is_const);
1675 for eid in &all_ids {
1676 if let Some(constraints) = info.type_env.expr_constraints.get(eid) {
1677 for c in constraints {
1678 eprintln!(" constraint: tier={} rust={} context={} source={:?}",
1679 c.ty.confidence_tier(),
1680 c.ty.to_rust_string(self.interner),
1681 c.context,
1682 match &c.ty {
1683 crate::type_repr::TypeRepr::CType { source, .. } => format!("{:?}", source),
1684 crate::type_repr::TypeRepr::RustType { source, .. } => format!("{:?}", source),
1685 crate::type_repr::TypeRepr::Inferred(i) => format!("Inferred({:?})", std::mem::discriminant(i)),
1686 }
1687 );
1688 }
1689 }
1690 }
1691 }
1692 eprintln!(" params_str: {}", params_str);
1693 eprintln!(" return_type: {}", return_type);
1695 eprintln!(" is_bool_return: {}", info.is_bool_return);
1696 if let Some(ty) = info.get_return_type() {
1697 eprintln!(" return TypeRepr: tier={} rust={}", ty.confidence_tier(), ty.to_rust_string(self.interner));
1698 }
1699 if !info.type_env.return_constraints.is_empty() {
1701 eprintln!(" return_constraints:");
1702 for c in &info.type_env.return_constraints {
1703 eprintln!(" tier={} rust={} context={}", c.ty.confidence_tier(), c.ty.to_rust_string(self.interner), c.context);
1704 }
1705 }
1706 if let ParseResult::Expression(ref expr) = info.parse_result {
1708 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
1709 eprintln!(" root expr constraints:");
1710 for c in constraints {
1711 eprintln!(" tier={} rust={} context={}",
1712 c.ty.confidence_tier(),
1713 c.ty.to_rust_string(self.interner),
1714 c.context,
1715 );
1716 }
1717 }
1718 }
1719 eprintln!("=== End type dump ===");
1720 }
1721
1722 fn dump_ast_comment_for_expr(&mut self, name_str: &str, parse_result: &ParseResult) {
1723 if self.dump_ast_for.as_deref() != Some(name_str) {
1724 return;
1725 }
1726 let sexp = match parse_result {
1727 ParseResult::Expression(expr) => {
1728 let mut buf = Vec::new();
1729 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1730 let _ = printer.print_expr(expr);
1731 String::from_utf8_lossy(&buf).into_owned()
1732 }
1733 ParseResult::Statement(block_items) => {
1734 let mut buf = Vec::new();
1735 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1736 for item in block_items {
1737 if let BlockItem::Stmt(stmt) = item {
1738 let _ = printer.print_stmt(stmt);
1739 } else if let BlockItem::Decl(decl) = item {
1740 let _ = printer.print_declaration(decl);
1741 }
1742 }
1743 String::from_utf8_lossy(&buf).into_owned()
1744 }
1745 ParseResult::Unparseable(msg) => {
1746 format!("(unparseable: {})", msg.as_deref().unwrap_or("unknown"))
1747 }
1748 };
1749 self.writeln(&format!("// [AST dump for {}]", name_str));
1750 for line in sexp.lines() {
1751 self.writeln(&format!("// {}", line));
1752 }
1753 }
1754
1755 fn dump_ast_comment_for_body(&mut self, name_str: &str, body: &CompoundStmt) {
1757 if self.dump_ast_for.as_deref() != Some(name_str) {
1758 return;
1759 }
1760 let mut buf = Vec::new();
1761 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1762 for item in &body.items {
1763 match item {
1764 BlockItem::Stmt(stmt) => { let _ = printer.print_stmt(stmt); }
1765 BlockItem::Decl(decl) => { let _ = printer.print_declaration(decl); }
1766 }
1767 }
1768 let sexp = String::from_utf8_lossy(&buf).into_owned();
1769 self.writeln(&format!("// [AST dump for {}]", name_str));
1770 for line in sexp.lines() {
1771 self.writeln(&format!("// {}", line));
1772 }
1773 }
1774
1775 fn try_expand_call_as_lvalue_syn(&mut self, func: &Expr, args: &[Expr],
1779 info: Option<&MacroInferInfo>) -> Option<syn::Expr> {
1780 if let ExprKind::Ident(name) = &func.kind {
1781 if self.should_emit_as_macro_call(*name) {
1782 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
1783 if let ParseResult::Expression(body) = ¯o_info.parse_result {
1784 let body = body.clone();
1785 let saved_params = std::mem::take(&mut self.param_substitutions);
1786 for (i, param) in macro_info.params.iter().enumerate() {
1787 if let Some(arg) = args.get(i) {
1788 let arg_syn = self.build_syn_expr(arg, info);
1789 let arg_str = crate::syn_codegen::expr_to_string(&arg_syn);
1790 self.param_substitutions.insert(param.name, arg_str);
1791 }
1792 }
1793 let body_syn = self.build_syn_expr(&body, info);
1794 self.param_substitutions = saved_params;
1795 return Some(body_syn);
1796 }
1797 }
1798 }
1799 }
1800 None
1801 }
1802
1803
1804 fn wrap_as_bool_condition_inline(&self, expr: &Expr, expr_str: &str) -> String {
1806 self.wrap_as_bool_condition(expr, expr_str, None)
1807 }
1808
1809 fn infer_expr_type_inline(&self, expr: &Expr) -> Option<UnifiedType> {
1811 self.infer_expr_type_unified(expr, None)
1812 }
1813
1814 fn type_name_to_type_str_readonly(&self, type_name: &crate::ast::TypeName) -> String {
1816 let pointer_count = type_name.declarator.as_ref()
1818 .map(|d| d.derived.iter().filter(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer(_))).count())
1819 .unwrap_or(0);
1820 let is_const_ptr = pointer_count == 1 && type_name.specs.qualifiers.is_const;
1826 let base = self.base_type_str_readonly(&type_name.specs.type_specs);
1828 let mut result = base;
1830 for _ in 0..pointer_count {
1831 let prefix = if is_const_ptr { "*const " } else { "*mut " };
1832 result = format!("{}{}", prefix, result);
1833 }
1834 result
1835 }
1836
1837 fn base_type_str_readonly(&self, type_specs: &[TypeSpec]) -> String {
1839 for spec in type_specs {
1841 if let TypeSpec::TypedefName(name) = spec {
1842 return self.interner.get(*name).to_string();
1843 }
1844 }
1845 for spec in type_specs {
1847 match spec {
1848 TypeSpec::Struct(s) | TypeSpec::Union(s) => {
1849 if let Some(n) = &s.name {
1850 return self.interner.get(*n).to_string();
1851 }
1852 }
1853 TypeSpec::Enum(e) => {
1854 if let Some(n) = &e.name {
1855 return self.interner.get(*n).to_string();
1856 }
1857 }
1858 _ => {}
1859 }
1860 }
1861 let mut is_void = false;
1862 let mut is_char = false;
1863 let mut is_int = false;
1864 let mut is_short = false;
1865 let mut is_long = 0usize;
1866 let mut is_unsigned = false;
1867 for spec in type_specs {
1868 match spec {
1869 TypeSpec::Void => is_void = true,
1870 TypeSpec::Char => is_char = true,
1871 TypeSpec::Int => is_int = true,
1872 TypeSpec::Short => is_short = true,
1873 TypeSpec::Long => is_long += 1,
1874 TypeSpec::Unsigned => is_unsigned = true,
1875 TypeSpec::Signed => {}
1876 TypeSpec::Bool => return "bool".to_string(),
1877 _ => {}
1878 }
1879 }
1880 if is_void { return "c_void".to_string(); }
1881 if is_char { return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() }; }
1882 if is_short { return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() }; }
1883 if is_long >= 2 { return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() }; }
1884 if is_long == 1 { return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() }; }
1885 if is_int || is_unsigned { return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() }; }
1886 "c_int".to_string()
1887 }
1888
1889 fn infer_expr_type(&self, expr: &Expr, info: &MacroInferInfo) -> Option<UnifiedType> {
1891 self.infer_expr_type_unified(expr, Some(info))
1892 }
1893
1894 fn infer_expr_type_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> Option<UnifiedType> {
1903 match &expr.kind {
1904 ExprKind::Ident(name) => {
1905 if let Some(ut) = self.current_param_types.get(name) {
1907 return Some(ut.clone());
1908 }
1909 if let Some(info) = info {
1911 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
1913 let mut best: Option<(UnifiedType, u8)> = None;
1914 for expr_id in expr_ids {
1915 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
1916 for c in constraints {
1917 if c.ty.is_void() { continue; }
1918 let tier = c.ty.confidence_tier();
1919 if best.is_none() || tier < best.as_ref().unwrap().1 {
1920 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
1921 }
1922 }
1923 }
1924 }
1925 if let Some((ut, _)) = best {
1926 return Some(ut);
1927 }
1928 }
1929 if let Some(constraints) = info.type_env.param_constraints.get(name) {
1931 let mut best: Option<(UnifiedType, u8)> = None;
1932 for c in constraints {
1933 if c.ty.is_void() { continue; }
1934 let tier = c.ty.confidence_tier();
1935 if best.is_none() || tier < best.as_ref().unwrap().1 {
1936 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
1937 }
1938 }
1939 if let Some((ut, _)) = best {
1940 return Some(ut);
1941 }
1942 }
1943 }
1944 if let Some(dict) = self.rust_decl_dict {
1946 let name_str = self.interner.get(*name);
1947 if let Some(c) = dict.consts.get(name_str) {
1948 return Some(c.uty.clone());
1949 }
1950 if let Some(ty_str) = dict.static_types.get(name_str) {
1952 return Some(UnifiedType::from_rust_str(ty_str));
1953 }
1954 }
1955 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
1959 let enum_str = self.interner.get(enum_name).to_string();
1960 return Some(UnifiedType::Named(enum_str));
1961 }
1962 None
1963 }
1964 ExprKind::Cast { type_name, .. } => {
1965 Some(UnifiedType::from_rust_str(&self.type_name_to_type_str_readonly(type_name)))
1966 }
1967 ExprKind::Member { expr: base, member } | ExprKind::PtrMember { expr: base, member } => {
1968 let resolve_struct_name = |this: &Self| -> Option<String> {
1973 if let Some(info_ref) = info {
1975 if let Some(constraints) = info_ref.type_env.expr_constraints.get(&base.id) {
1976 if let Some(base_ty) = constraints.first().map(|c| &c.ty) {
1977 let sn = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
1978 base_ty.pointee_name()
1979 } else {
1980 base_ty.type_name()
1981 };
1982 if let Some(n) = sn {
1983 return Some(this.interner.get(n).to_string());
1984 }
1985 }
1986 }
1987 }
1988 let base_ut = this.infer_expr_type_unified(base, info)?;
1991 let target = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
1992 base_ut.inner_type()?
1993 } else {
1994 &base_ut
1995 };
1996 if let UnifiedType::Named(n) = target {
1997 return Some(n.clone());
1998 }
1999 None
2000 };
2001
2002 let member_str = self.interner.get(*member);
2003 let fd_ty: Option<UnifiedType> = self.fields_dict.and_then(|fd| {
2010 let struct_name_str = resolve_struct_name(self)?;
2011 let struct_name = self.interner.lookup(&struct_name_str)?;
2012 let member_ty = fd.member_type(struct_name, *member)?;
2013 let rust_ty = member_ty.to_rust_string(self.interner);
2014 if rust_ty.contains("/* fn */") {
2015 return None;
2016 }
2017 Some(UnifiedType::from_rust_str(&rust_ty))
2018 });
2019 let ftm_ty = self.field_type_map.get(member_str).cloned();
2020 match (&fd_ty, &ftm_ty) {
2023 (Some(fd_ut), Some(ftm_ut))
2024 if fd_ut.is_pointer() && ftm_ut.to_rust_string().starts_with('[') =>
2025 {
2026 return ftm_ty;
2027 }
2028 _ => {}
2029 }
2030 fd_ty.or(ftm_ty)
2031 }
2032 ExprKind::Deref(inner) => {
2033 let inner_ut = self.infer_expr_type_unified(inner, info)?;
2034 inner_ut.inner_type().cloned()
2035 }
2036 ExprKind::Index { expr: base, .. } => {
2037 let base_ut = self.infer_expr_type_unified(base, info)?;
2040 base_ut.inner_type().cloned()
2041 }
2042 ExprKind::Binary { op, lhs, rhs } => {
2043 match op {
2044 BinOp::Shl | BinOp::Shr => self.infer_expr_type_unified(lhs, info),
2045 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => {
2046 let lt = self.infer_expr_type_unified(lhs, info);
2047 let rt = self.infer_expr_type_unified(rhs, info);
2048 match (<, &rt) {
2049 (Some(l), Some(r)) => {
2050 let ls = l.to_rust_string();
2051 let rs = r.to_rust_string();
2052 wider_integer_type(&ls, &rs)
2053 .map(|w| UnifiedType::from_rust_str(w))
2054 .or(lt)
2055 }
2056 (Some(_), None) => lt,
2057 (None, Some(_)) => rt,
2058 _ => None,
2059 }
2060 }
2061 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt
2062 | BinOp::Le | BinOp::Ge | BinOp::LogAnd | BinOp::LogOr => {
2063 Some(UnifiedType::Bool)
2064 }
2065 _ => {
2066 if *op == BinOp::Sub {
2069 let lp = self.is_pointer_expr_unified(lhs, info)
2070 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
2071 let rp = self.is_pointer_expr_unified(rhs, info)
2072 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
2073 if lp && rp {
2074 return Some(UnifiedType::Named("isize".to_string()));
2075 }
2076 }
2077 let lt = self.infer_expr_type_unified(lhs, info);
2078 if lt.is_some() { return lt; }
2079 self.infer_expr_type_unified(rhs, info)
2080 }
2081 }
2082 }
2083 ExprKind::BitNot(inner) | ExprKind::UnaryMinus(inner) => self.infer_expr_type_unified(inner, info),
2084 ExprKind::CharLit(_) => Some(UnifiedType::from_rust_str("i8")),
2085 ExprKind::UIntLit(_) => Some(UnifiedType::Int { signed: false, size: crate::unified_type::IntSize::LongLong }),
2086 ExprKind::Sizeof(_) | ExprKind::SizeofType(_) => Some(UnifiedType::Named("usize".to_string())),
2091 ExprKind::Call { func, .. } => {
2092 if let ExprKind::Member { expr: receiver, member, .. } = &func.kind {
2094 let method_name = self.interner.get(*member);
2095 if matches!(method_name, "offset" | "wrapping_add" | "wrapping_sub" | "wrapping_offset") {
2096 return self.infer_expr_type_unified(receiver, info);
2097 }
2098 }
2099 if let ExprKind::Ident(name) = &func.kind {
2100 let func_name = self.interner.get(*name);
2101 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2102 return Some(ret_ut.clone());
2103 }
2104 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2106 if let Some(ty) = macro_info.get_return_type() {
2107 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2108 }
2109 }
2110 if let Some(dict) = self.inline_fn_dict {
2112 if let Some(func_def) = dict.get(*name) {
2113 let base = self.base_type_str_readonly(&func_def.specs.type_specs);
2115 let mut result = base;
2116 let pointer_count = func_def.declarator.derived.iter()
2117 .take_while(|d| !matches!(d, crate::ast::DerivedDecl::Function(_)))
2118 .filter(|d| matches!(d, crate::ast::DerivedDecl::Pointer(_)))
2119 .count();
2120 let is_const_ptr = pointer_count == 1
2121 && func_def.specs.qualifiers.is_const;
2122 for _ in 0..pointer_count {
2123 let prefix = if is_const_ptr { "*const " } else { "*mut " };
2124 result = format!("{}{}", prefix, result);
2125 }
2126 return Some(UnifiedType::from_rust_str(&result));
2127 }
2128 }
2129 }
2130 None
2131 }
2132 ExprKind::MacroCall { name, expanded, .. } => {
2133 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2134 if let Some(ty) = macro_info.get_return_type() {
2135 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2136 }
2137 }
2138 self.infer_expr_type_unified(expanded, info)
2139 }
2140 ExprKind::Conditional { then_expr, else_expr, .. } => {
2141 if is_null_literal(then_expr) {
2142 return self.infer_expr_type_unified(else_expr, info);
2143 }
2144 if is_null_literal(else_expr) {
2145 return self.infer_expr_type_unified(then_expr, info);
2146 }
2147 let tt = self.infer_expr_type_unified(then_expr, info);
2148 let et = self.infer_expr_type_unified(else_expr, info);
2149 match (&tt, &et) {
2150 (Some(t), Some(e)) if t.is_void_pointer() && e.is_concrete_pointer() => et,
2151 (Some(t), Some(e)) if e.is_void_pointer() && t.is_concrete_pointer() => tt,
2152 (Some(_), _) => tt,
2153 (None, _) => et,
2154 }
2155 }
2156 _ => None,
2157 }
2158 }
2159
2160 fn is_pointer_expr_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2162 match &expr.kind {
2163 ExprKind::Ident(name) => {
2164 if let Some(ut) = self.current_param_types.get(name) {
2165 return ut.is_pointer();
2166 }
2167 if let Some(info) = info {
2168 if let Some(constraints) = info.type_env.param_constraints.get(name) {
2169 for c in constraints {
2170 if is_type_repr_pointer(&c.ty) {
2171 return true;
2172 }
2173 }
2174 }
2175 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
2176 for expr_id in expr_ids {
2177 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
2178 for c in constraints {
2179 if is_type_repr_pointer(&c.ty) {
2180 return true;
2181 }
2182 }
2183 }
2184 }
2185 }
2186 }
2187 false
2188 }
2189 ExprKind::Cast { type_name, .. } => {
2190 type_name.declarator.as_ref()
2191 .map(|d| d.derived.iter().any(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer { .. })))
2192 .unwrap_or(false)
2193 }
2194 ExprKind::AddrOf(_) => true,
2195 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => {
2196 let member_str = self.interner.get(*member);
2197 self.field_type_map.get(member_str).is_some_and(|ut| ut.is_pointer())
2198 }
2199 ExprKind::Deref(inner) => {
2200 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
2201 if let Some(derefed) = ut.inner_type() {
2202 return derefed.is_pointer();
2203 }
2204 }
2205 false
2206 }
2207 ExprKind::Call { func, .. } | ExprKind::MacroCall { expanded: func, .. } => {
2208 let check_func = match &expr.kind {
2209 ExprKind::MacroCall { name, .. } => {
2210 if let Some(callee) = self.macro_ctx.macros.get(name) {
2211 for c in &callee.type_env.return_constraints {
2212 if is_type_repr_pointer(&c.ty) { return true; }
2213 }
2214 }
2215 func
2216 }
2217 _ => func,
2218 };
2219 if let ExprKind::Ident(name) = &check_func.kind {
2220 if let Some(callee) = self.macro_ctx.macros.get(name) {
2221 for c in &callee.type_env.return_constraints {
2222 if is_type_repr_pointer(&c.ty) { return true; }
2223 }
2224 }
2225 if let Some(ret_ut) = self.get_callee_return_type(self.interner.get(*name)) {
2226 return ret_ut.is_pointer();
2227 }
2228 }
2229 false
2230 }
2231 ExprKind::Binary { op, lhs, rhs } => {
2232 match op {
2233 BinOp::Add => self.is_pointer_expr_unified(lhs, info) || self.is_pointer_expr_unified(rhs, info),
2234 BinOp::Sub => self.is_pointer_expr_unified(lhs, info) && !self.is_pointer_expr_unified(rhs, info),
2235 _ => false,
2236 }
2237 }
2238 _ => false,
2239 }
2240 }
2241
2242 fn is_option_fn_pointer_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2249 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2253 let member_str = self.interner.get(*member);
2254 if let Some(ut) = self.field_type_map.get(member_str) {
2255 let ty_str = ut.to_rust_string();
2256 if type_str_is_fn_pointer(&ty_str) {
2257 return true;
2258 }
2259 if let Some(dict) = self.rust_decl_dict {
2260 if let Some(alias) = dict.types.get(&ty_str) {
2261 if type_str_is_fn_pointer(&alias.ty) {
2262 return true;
2263 }
2264 }
2265 }
2266 }
2267 }
2268 let Some(ut) = self.infer_expr_type_unified(expr, info) else { return false };
2269 let ty_str = ut.to_rust_string();
2270 if type_str_is_fn_pointer(&ty_str) {
2271 return true;
2272 }
2273 if let Some(dict) = self.rust_decl_dict {
2275 if let Some(alias) = dict.types.get(&ty_str) {
2276 if type_str_is_fn_pointer(&alias.ty) {
2277 return true;
2278 }
2279 }
2280 }
2281 false
2282 }
2283
2284 fn wrap_as_bool_condition(&self, expr: &Expr, expr_str: &str, info: Option<&MacroInferInfo>) -> String {
2286 if self.is_bool_expr_with_dict(expr) {
2287 return expr_str.to_string();
2288 }
2289 if let ExprKind::Ident(name) = &expr.kind {
2291 if let Some(ut) = self.current_param_types.get(name) {
2292 if ut.is_bool() {
2293 return expr_str.to_string();
2294 }
2295 }
2296 }
2297 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2299 let member_str = self.interner.get(*member);
2300 if let Some(ut) = self.field_type_map.get(member_str) {
2301 if ut.is_bool() {
2302 return expr_str.to_string();
2303 }
2304 }
2305 }
2306 if let ExprKind::Call { func, args, .. } = &expr.kind {
2308 if let ExprKind::Ident(name) = &func.kind {
2309 if self.interner.get(*name) == "__builtin_expect" && !args.is_empty() {
2310 return self.wrap_as_bool_condition(&args[0], expr_str, info);
2311 }
2312 }
2313 }
2314 if expr_str.ends_with(" as bool)") || expr_str.ends_with("!= 0)") || expr_str.ends_with(".is_null()") {
2315 return expr_str.to_string();
2316 }
2317 if self.is_option_fn_pointer_expr(expr, info) {
2320 return format!("{}.is_some()", expr_str);
2321 }
2322 if self.is_pointer_expr_unified(expr, info)
2323 || self.infer_expr_type_unified(expr, info).is_some_and(|ut| ut.is_pointer()) {
2324 return format!("!({}).is_null()", expr_str);
2329 }
2330 format!("({} != 0)", strip_outer_parens(expr_str))
2331 }
2332
2333 fn needs_my_perl_for_call(&self, func_name: crate::InternedStr, actual_arg_count: usize) -> bool {
2340 if !self.perl_threaded {
2344 return false;
2345 }
2346 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2347 if callee_info.is_thx_dependent {
2348 let expected_count = callee_info.params.len() + 1;
2350 return actual_arg_count + 1 == expected_count;
2352 }
2353 }
2354 false
2355 }
2356
2357 fn is_static_array_expr(&self, expr: &Expr) -> bool {
2359 if let ExprKind::Ident(name) = &expr.kind {
2360 let name_str = self.interner.get(*name);
2361 self.bindings_info.static_arrays.contains(name_str)
2362 } else {
2363 false
2364 }
2365 }
2366
2367 fn is_array_like_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2375 if self.is_static_array_expr(expr) {
2376 return true;
2377 }
2378 if let ExprKind::Member { expr: base, member }
2380 | ExprKind::PtrMember { expr: base, member } = &expr.kind
2381 {
2382 if let (Some(fd), Some(info)) = (self.fields_dict, info) {
2383 if let Some(constraints) = info.type_env.expr_constraints.get(&base.id) {
2384 if let Some(base_type) = constraints.first().map(|c| &c.ty) {
2385 let struct_name = match &expr.kind {
2386 ExprKind::PtrMember { .. } => base_type.pointee_name(),
2387 _ => base_type.type_name(),
2388 };
2389 if let Some(sn) = struct_name {
2390 if fd.is_flexible_array_field(sn, *member) {
2391 return false;
2392 }
2393 }
2394 }
2395 }
2396 }
2397 }
2398 if let Some(ut) = self.infer_expr_type_unified(expr, info) {
2399 let s = ut.to_rust_string();
2400 if s.starts_with('[') && s.contains(';') {
2401 return true;
2402 }
2403 }
2404 false
2405 }
2406
2407 fn is_bitfield_method(&self, member_name: &str) -> bool {
2411 self.bindings_info.bitfield_methods.values()
2412 .any(|methods| methods.contains(member_name))
2413 }
2414
2415 fn get_callee_generic_params(&self, func_name: InternedStr) -> Option<&HashMap<i32, String>> {
2417 let callee_info = self.macro_ctx.macros.get(&func_name)?;
2418 if callee_info.generic_type_params.is_empty() {
2419 return None;
2420 }
2421 if callee_info.generic_type_params.keys().any(|&k| k >= 0) {
2422 Some(&callee_info.generic_type_params)
2423 } else {
2424 None
2425 }
2426 }
2427
2428 fn is_enum_cast_target(&self, type_name: &crate::ast::TypeName) -> bool {
2430 for spec in &type_name.specs.type_specs {
2431 match spec {
2432 TypeSpec::TypedefName(name) => return self.enum_dict.is_target_enum(*name),
2433 TypeSpec::Enum(_) => return true,
2434 _ => {}
2435 }
2436 }
2437 false
2438 }
2439
2440 fn callee_expects_literal_string(&self, func_name: InternedStr, arg_index: usize) -> bool {
2442 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2443 return callee_info.literal_string_params.contains(&arg_index);
2444 }
2445 false
2446 }
2447
2448 fn get_callee_param_type(&self, func_name: &str, arg_index: usize) -> Option<&UnifiedType> {
2450 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2451 f.params.get(arg_index).map(|p| &p.uty)
2452 })
2453 }
2454
2455 fn get_callee_param_type_extended(&mut self, func_name: &str, arg_index: usize) -> Option<UnifiedType> {
2457 if let Some(ut) = libc_fn_param_type(func_name, arg_index) {
2461 return Some(ut);
2462 }
2463 if let Some(ut) = self.get_callee_param_type(func_name, arg_index) {
2465 return Some(ut.clone());
2466 }
2467 if let Some(interned) = self.interner.lookup(func_name) {
2468 if let Some(dict) = self.inline_fn_dict {
2470 if let Some(func_def) = dict.get(interned) {
2471 for d in &func_def.declarator.derived {
2472 if let DerivedDecl::Function(param_list) = d {
2473 if let Some(param) = param_list.params.get(arg_index) {
2474 let ty = self.param_type_only(param);
2475 return Some(UnifiedType::from_rust_str(&ty));
2476 }
2477 break;
2478 }
2479 }
2480 }
2481 }
2482 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2484 let macro_param_idx = if self.perl_threaded && macro_info.is_thx_dependent {
2487 if arg_index == 0 {
2488 return Some(UnifiedType::from_rust_str("*mut PerlInterpreter"));
2489 }
2490 arg_index - 1
2491 } else {
2492 arg_index
2493 };
2494 if let Some(param) = macro_info.params.get(macro_param_idx) {
2495 if let Some(mut ty) = best_constraint_for_macro_param(macro_info, param) {
2499 let should_be_const = macro_info
2502 .const_pointer_positions
2503 .contains(¯o_param_idx);
2504 if should_be_const {
2505 ty.make_outer_pointer_const();
2506 } else if ty.has_outer_pointer() {
2507 ty.make_outer_pointer_mut();
2508 }
2509 let rust_ty = ty.to_rust_string(self.interner);
2510 return Some(UnifiedType::from_rust_str(&rust_ty));
2511 }
2512 }
2513 }
2514 }
2515 None
2516 }
2517
2518 fn callee_param_is_bool(&self, func_name: &str, arg_index: usize) -> bool {
2520 if let Some(param_ut) = self.get_callee_param_type(func_name, arg_index) {
2522 return param_ut.is_bool();
2523 }
2524 if let Some(interned) = self.interner.lookup(func_name) {
2526 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2527 let macro_arg_index = if self.perl_threaded
2530 && macro_info.is_thx_dependent
2531 && arg_index > 0
2532 {
2533 arg_index - 1
2534 } else {
2535 arg_index
2536 };
2537 if let Some(param) = macro_info.params.get(macro_arg_index) {
2538 if let Some(expr_ids) = macro_info.type_env.param_to_exprs.get(¶m.name) {
2540 for expr_id in expr_ids {
2541 if let Some(constraints) = macro_info.type_env.expr_constraints.get(expr_id) {
2542 for c in constraints {
2543 let rust_ty = c.ty.to_rust_string(self.interner);
2544 if rust_ty == "bool" {
2545 return true;
2546 }
2547 }
2548 }
2549 }
2550 }
2551 }
2552 }
2553 if let Some(dict) = self.inline_fn_dict {
2555 if let Some(func_def) = dict.get(interned) {
2556 for d in &func_def.declarator.derived {
2557 if let DerivedDecl::Function(param_list) = d {
2558 if let Some(param) = param_list.params.get(arg_index) {
2559 let has_bool = param.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2560 let has_pointer = param.declarator.as_ref().map_or(false, |decl| {
2561 decl.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)))
2562 });
2563 if has_bool && !has_pointer {
2564 return true;
2565 }
2566 }
2567 break;
2568 }
2569 }
2570 }
2571 }
2572 }
2573 false
2574 }
2575
2576 fn get_callee_return_type(&self, func_name: &str) -> Option<&UnifiedType> {
2578 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2579 f.uret_ty.as_ref()
2580 })
2581 }
2582
2583 fn is_rust_enum_type(&self, ut: &UnifiedType) -> bool {
2587 if let UnifiedType::Named(name) = ut {
2588 if let Some(dict) = self.rust_decl_dict {
2589 return dict.enums.contains(name.as_str());
2590 }
2591 }
2592 false
2593 }
2594
2595 fn is_bool_expr_with_dict(&self, expr: &Expr) -> bool {
2597 if is_boolean_expr_recursive(expr, self.interner) {
2598 return true;
2599 }
2600 if let ExprKind::Index { expr: base, .. } = &expr.kind {
2602 if let ExprKind::Ident(name) = &base.kind {
2603 if let Some(dict) = self.rust_decl_dict {
2604 let name_str = self.interner.get(*name);
2605 if let Some(c) = dict.consts.get(name_str) {
2606 if let Some(inner) = c.uty.inner_type() {
2607 if inner.is_bool() {
2608 return true;
2609 }
2610 }
2611 }
2612 if dict.statics.contains(name_str) && name_str.starts_with("PL_valid_types_") {
2614 return true;
2615 }
2616 }
2617 }
2618 }
2619 if let ExprKind::Ident(name) = &expr.kind {
2621 if let Some(ut) = self.current_param_types.get(name) {
2622 if ut.is_bool() {
2623 return true;
2624 }
2625 }
2626 }
2627 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2629 let member_str = self.interner.get(*member);
2630 if let Some(ut) = self.field_type_map.get(member_str) {
2631 if ut.is_bool() {
2632 return true;
2633 }
2634 }
2635 }
2636 if let ExprKind::Call { func, .. } = &expr.kind {
2638 if let ExprKind::Ident(name) = &func.kind {
2639 if self.bool_return_macros.contains(name) {
2641 return true;
2642 }
2643 let func_name = self.interner.get(*name);
2644 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2646 return ret_ut.is_bool();
2647 }
2648 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2650 if let Some(ty) = macro_info.get_return_type() {
2651 let rust_ty = ty.to_rust_string(self.interner);
2652 return rust_ty == "bool";
2653 }
2654 }
2655 if let Some(dict) = self.inline_fn_dict {
2657 if let Some(func_def) = dict.get(*name) {
2658 let has_bool_return = func_def.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2659 let has_return_pointer = func_def.declarator.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)));
2660 if has_bool_return && !has_return_pointer {
2661 return true;
2662 }
2663 }
2664 }
2665 }
2666 }
2667 if let ExprKind::MacroCall { name, .. } = &expr.kind {
2669 if self.bool_return_macros.contains(name) {
2670 return true;
2671 }
2672 }
2673 false
2674 }
2675
2676 fn find_literal_string_ident<'b>(&self, expr: &'b Expr) -> Option<&'b InternedStr> {
2679 match &expr.kind {
2680 ExprKind::Ident(name) if self.current_literal_string_params.contains(name) => {
2681 Some(name)
2682 }
2683 ExprKind::Call { func, args } if args.len() == 1 => {
2684 if let ExprKind::Ident(fname) = &func.kind {
2686 let func_name = self.interner.get(*fname);
2687 if func_name == "ASSERT_IS_LITERAL"
2688 || func_name == "ASSERT_IS_PTR"
2689 || func_name == "ASSERT_NOT_PTR"
2690 {
2691 return self.find_literal_string_ident(&args[0]);
2692 }
2693 }
2694 None
2695 }
2696 _ => None,
2697 }
2698 }
2699
2700
2701 fn should_emit_as_macro_call(&self, name: crate::InternedStr) -> bool {
2708 if let Some(info) = self.macro_ctx.macros.get(&name) {
2710 return info.is_parseable() && !info.calls_unavailable;
2712 }
2713 false
2714 }
2715
2716 fn unknown_marker(&mut self) -> &'static str {
2718 self.incomplete_count += 1;
2719 "/* unknown */"
2720 }
2721
2722 fn todo_marker(&mut self, msg: &str) -> String {
2724 self.incomplete_count += 1;
2725 format!("/* TODO: {} */", msg)
2726 }
2727
2728 fn type_marker(&mut self) -> &'static str {
2730 self.incomplete_count += 1;
2731 "/* type */"
2732 }
2733
2734 fn collect_decl_names(&mut self, decl: &Declaration) {
2737 let base_type = self.decl_specs_to_rust(&decl.specs);
2738 for init_decl in &decl.declarators {
2739 if let Some(name) = init_decl.declarator.name {
2740 self.current_local_names.insert(name);
2741 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2742 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2743 }
2744 }
2745 }
2746
2747 fn collect_local_names_recursive(&mut self, body: &CompoundStmt) {
2753 for item in &body.items {
2754 self.collect_local_names_from_block_item(item);
2755 }
2756 }
2757
2758 fn collect_local_names_from_block_item(&mut self, item: &BlockItem) {
2759 match item {
2760 BlockItem::Decl(d) => self.collect_decl_names(d),
2761 BlockItem::Stmt(s) => self.collect_local_names_from_stmt(s),
2762 }
2763 }
2764
2765 fn collect_local_names_from_stmt(&mut self, stmt: &Stmt) {
2766 match stmt {
2767 Stmt::Compound(c) => self.collect_local_names_recursive(c),
2768 Stmt::If { then_stmt, else_stmt, cond, .. } => {
2769 self.collect_local_names_from_expr(cond);
2770 self.collect_local_names_from_stmt(then_stmt);
2771 if let Some(es) = else_stmt {
2772 self.collect_local_names_from_stmt(es);
2773 }
2774 }
2775 Stmt::Switch { body, expr, .. } => {
2776 self.collect_local_names_from_expr(expr);
2777 self.collect_local_names_from_stmt(body);
2778 }
2779 Stmt::While { body, cond, .. } => {
2780 self.collect_local_names_from_expr(cond);
2781 self.collect_local_names_from_stmt(body);
2782 }
2783 Stmt::DoWhile { body, cond, .. } => {
2784 self.collect_local_names_from_stmt(body);
2785 self.collect_local_names_from_expr(cond);
2786 }
2787 Stmt::For { init, cond, step, body, .. } => {
2788 if let Some(i) = init {
2789 match i {
2790 ForInit::Decl(d) => self.collect_decl_names(d),
2791 ForInit::Expr(e) => self.collect_local_names_from_expr(e),
2792 }
2793 }
2794 if let Some(c) = cond { self.collect_local_names_from_expr(c); }
2795 if let Some(s) = step { self.collect_local_names_from_expr(s); }
2796 self.collect_local_names_from_stmt(body);
2797 }
2798 Stmt::Expr(Some(e), _) => self.collect_local_names_from_expr(e),
2799 Stmt::Return(Some(e), _) => self.collect_local_names_from_expr(e),
2800 Stmt::Label { stmt, .. } | Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => {
2801 self.collect_local_names_from_stmt(stmt);
2802 }
2803 _ => {}
2804 }
2805 }
2806
2807 fn collect_local_names_from_expr(&mut self, expr: &Expr) {
2808 if let ExprKind::StmtExpr(c) = &expr.kind {
2809 self.collect_local_names_recursive(c);
2810 }
2811 match &expr.kind {
2814 ExprKind::Binary { lhs, rhs, .. }
2815 | ExprKind::Assign { lhs, rhs, .. }
2816 | ExprKind::Comma { lhs, rhs } => {
2817 self.collect_local_names_from_expr(lhs);
2818 self.collect_local_names_from_expr(rhs);
2819 }
2820 ExprKind::Conditional { cond, then_expr, else_expr } => {
2821 self.collect_local_names_from_expr(cond);
2822 self.collect_local_names_from_expr(then_expr);
2823 self.collect_local_names_from_expr(else_expr);
2824 }
2825 ExprKind::Cast { expr: e, .. }
2826 | ExprKind::AddrOf(e) | ExprKind::Deref(e)
2827 | ExprKind::UnaryPlus(e) | ExprKind::UnaryMinus(e)
2828 | ExprKind::BitNot(e) | ExprKind::LogNot(e)
2829 | ExprKind::PreInc(e) | ExprKind::PreDec(e)
2830 | ExprKind::PostInc(e) | ExprKind::PostDec(e)
2831 | ExprKind::Sizeof(e)
2832 | ExprKind::Member { expr: e, .. } | ExprKind::PtrMember { expr: e, .. } => {
2833 self.collect_local_names_from_expr(e);
2834 }
2835 ExprKind::Call { func, args } => {
2836 self.collect_local_names_from_expr(func);
2837 for a in args { self.collect_local_names_from_expr(a); }
2838 }
2839 ExprKind::Index { expr: e, index } => {
2840 self.collect_local_names_from_expr(e);
2841 self.collect_local_names_from_expr(index);
2842 }
2843 _ => {}
2844 }
2845 }
2846
2847 fn collect_decl_types(&mut self, decl: &Declaration) {
2850 let base_type = self.decl_specs_to_rust(&decl.specs);
2851 for init_decl in &decl.declarators {
2852 if let Some(name) = init_decl.declarator.name {
2853 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2854 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2855 }
2856 }
2857 }
2858
2859 fn writeln(&mut self, s: &str) {
2861 self.buffer.push_str(s);
2862 self.buffer.push('\n');
2863 }
2864
2865 fn into_generated_code(self) -> GeneratedCode {
2867 GeneratedCode {
2868 code: self.buffer,
2869 incomplete_count: self.incomplete_count,
2870 unresolved_names: self.unresolved_names,
2871 used_libc_fns: self.used_libc_fns,
2872 codegen_errors: self.codegen_errors,
2873 }
2874 }
2875
2876 pub fn generate_macro(mut self, info: &MacroInferInfo) -> GeneratedCode {
2878 let name_str = self.interner.get(info.name);
2879
2880 for p in &info.params {
2882 self.current_local_names.insert(p.name);
2883 }
2884
2885 self.current_type_param_map = info.generic_type_params.iter()
2887 .filter(|(idx, _)| **idx >= 0)
2888 .filter_map(|(idx, generic_name)| {
2889 info.params.get(*idx as usize).map(|p| (p.name, generic_name.clone()))
2890 })
2891 .collect();
2892
2893 for (name, _) in &self.current_type_param_map {
2896 self.current_local_names.remove(name);
2897 }
2898
2899 self.current_literal_string_params = info.literal_string_params.iter()
2901 .filter_map(|&idx| info.params.get(idx).map(|p| p.name))
2902 .collect();
2903
2904 let generic_clause = self.build_generic_clause(info);
2906
2907 let params_with_types = self.build_param_list(info);
2910
2911 let return_type = self.get_return_type(info);
2913 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
2914
2915 if self.dump_types_for.as_deref() == Some(name_str) {
2917 self.dump_type_info(name_str, info, ¶ms_with_types, &return_type);
2918 }
2919
2920 let thx_param = if self.perl_threaded && info.is_thx_dependent {
2923 "my_perl: *mut PerlInterpreter"
2924 } else {
2925 ""
2926 };
2927
2928 let params_str = if thx_param.is_empty() {
2930 params_with_types.clone()
2931 } else if params_with_types.is_empty() {
2932 thx_param.to_string()
2933 } else {
2934 format!("{}, {}", thx_param, params_with_types)
2935 };
2936
2937 self.dump_ast_comment_for_expr(name_str, &info.parse_result);
2939
2940 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
2942 let generic_info = if !generic_clause.is_empty() { " [generic]" } else { "" };
2943 self.writeln(&format!("/// {}{}{} - macro function", name_str, thx_info, generic_info));
2944 self.writeln("#[inline]");
2945 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
2946
2947 self.writeln(&format!("pub unsafe fn {}{}({}) -> {} {{", name_str, generic_clause, params_str, return_type));
2949
2950 let needs_unsafe = info.has_unsafe_ops();
2952 let body_indent = if needs_unsafe { " " } else { " " };
2953
2954 if needs_unsafe {
2955 self.writeln(" unsafe {");
2956 }
2957
2958 match &info.parse_result {
2959 ParseResult::Expression(expr) => {
2960 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
2961 let mut syn_expr = self.build_syn_expr_with_type_hint(expr, Some(info), type_hint.as_deref());
2962
2963 if self.current_return_type.as_ref().is_some_and(|ut| ut.is_void()) {
2964 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2965 self.writeln(&format!("{}{};", body_indent, s));
2966 } else if self.current_return_type.as_ref().is_some_and(|ut| ut.is_bool())
2967 && !self.is_bool_expr_with_dict(expr)
2968 && !crate::syn_codegen::is_bool_syn_expr(&syn_expr) {
2969 if self.is_pointer_expr_unified(expr, Some(info))
2970 || self.infer_expr_type_unified(expr, Some(info)).is_some_and(|ut| ut.is_pointer()) {
2971 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2972 self.writeln(&format!("{}!({}).is_null()", body_indent, s));
2975 } else {
2976 syn_expr = crate::syn_codegen::wrap_as_bool(syn_expr);
2977 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2978 self.writeln(&format!("{}{}", body_indent, s));
2979 }
2980 } else {
2981 syn_expr = self.cast_return_syn_expr_if_needed(expr, Some(info), syn_expr);
2982 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2983 self.writeln(&format!("{}{}", body_indent, s));
2984 }
2985 }
2986 ParseResult::Statement(block_items) => {
2987 for item in block_items {
2988 if let BlockItem::Stmt(stmt) = item {
2989 let rust_stmt = self.stmt_to_rust(stmt, info);
2990 self.writeln(&format!("{}{}", body_indent, rust_stmt));
2991 }
2992 }
2993 }
2994 ParseResult::Unparseable(_) => {
2995 self.writeln(&format!("{}unimplemented!()", body_indent));
2996 }
2997 }
2998
2999 if needs_unsafe {
3000 self.writeln(" }");
3001 }
3002
3003 self.writeln("}");
3004 self.writeln("");
3005
3006 self.into_generated_code()
3007 }
3008
3009 fn build_generic_clause(&self, info: &MacroInferInfo) -> String {
3011 if info.generic_type_params.is_empty() {
3012 return String::new();
3013 }
3014
3015 let mut params: Vec<&String> = info.generic_type_params.values().collect();
3017 params.sort();
3018 params.dedup();
3019
3020 format!("<{}>", params.iter().map(|s| s.as_str()).collect::<Vec<_>>().join(", "))
3021 }
3022
3023 fn build_param_list(&mut self, info: &MacroInferInfo) -> String {
3027 let mut_params = collect_mut_params(&info.parse_result, &info.params);
3028 let mut parts = Vec::new();
3029 for (i, p) in info.params.iter().enumerate() {
3030 if info.generic_type_params.contains_key(&(i as i32)) {
3031 continue;
3032 }
3033 let name = escape_rust_keyword(self.interner.get(p.name));
3034 let ty = self.get_param_type(p, info, i);
3035 self.current_param_types.insert(p.name, UnifiedType::from_rust_str(&ty));
3037 let mut_prefix = if mut_params.contains(&p.name) { "mut " } else { "" };
3038 parts.push(format!("{}{}: {}", mut_prefix, name, ty));
3039 }
3040 parts.join(", ")
3041 }
3042
3043 fn get_param_type(&mut self, param: &MacroParam, info: &MacroInferInfo, param_index: usize) -> String {
3045 if let Some(generic_name) = info.generic_type_params.get(&(param_index as i32)) {
3047 return generic_name.clone();
3048 }
3049
3050 if info.literal_string_params.contains(¶m_index) {
3052 return "&str".to_string();
3053 }
3054
3055 let should_be_const = self.const_pointer_positions.contains(¶m_index);
3056
3057 if let Some(mut ty) = best_constraint_for_macro_param(info, param) {
3058 if should_be_const {
3059 ty.make_outer_pointer_const();
3060 } else if ty.has_outer_pointer() {
3061 ty.make_outer_pointer_mut();
3063 }
3064 return self.type_repr_to_rust(&ty);
3065 }
3066
3067 self.unknown_marker().to_string()
3068 }
3069
3070 fn get_return_type(&mut self, info: &MacroInferInfo) -> String {
3076 if let Some(generic_name) = info.generic_type_params.get(&-1) {
3078 return generic_name.clone();
3079 }
3080
3081 if self.is_bool_return {
3083 return "bool".to_string();
3084 }
3085
3086 match &info.parse_result {
3087 ParseResult::Expression(expr) => {
3088 if let Some(ty) = info.get_return_type() {
3089 let mut ty_str = self.type_repr_to_rust(ty);
3090 if ty_str != "()" {
3091 if ty_str.contains("*mut") {
3093 if let Some(expr_ut) = self.infer_expr_type(expr, info) {
3094 if expr_ut.is_const_pointer() {
3095 ty_str = ty_str.replace("*mut", "*const");
3096 }
3097 }
3098 }
3099 return ty_str;
3100 }
3101 if let Some(ut) = self.infer_expr_type(expr, info) {
3105 let s = ut.to_rust_string();
3106 if s != "()" {
3107 return s;
3108 }
3109 }
3110 return ty_str;
3112 }
3113 self.unknown_marker().to_string()
3114 }
3115 ParseResult::Statement(_) => "()".to_string(),
3116 ParseResult::Unparseable(_) => "()".to_string(),
3117 }
3118 }
3119
3120 fn type_repr_to_rust(&mut self, ty: &crate::type_repr::TypeRepr) -> String {
3124 let result = ty.to_rust_string(self.interner);
3125 let result = self.substitute_type_params(&result);
3126 if result.contains("/*") {
3127 self.incomplete_count += 1;
3128 }
3129 result
3130 }
3131
3132 fn substitute_type_params(&self, type_str: &str) -> String {
3134 if self.current_type_param_map.is_empty() {
3135 return type_str.to_string();
3136 }
3137 let mut result = type_str.to_string();
3138 for (param_name, generic_name) in &self.current_type_param_map {
3139 let name_str = self.interner.get(*param_name);
3140 result = replace_word(&result, name_str, generic_name);
3142 }
3143 result
3144 }
3145
3146 fn detect_mutable_ptr_pattern<'b>(&self, compound: &'b CompoundStmt) -> Option<&'b Expr> {
3151 if compound.items.len() != 2 {
3153 return None;
3154 }
3155
3156 let decl = match &compound.items[0] {
3158 BlockItem::Decl(d) => d,
3159 _ => return None,
3160 };
3161
3162 if decl.declarators.len() != 1 {
3164 return None;
3165 }
3166 let init_decl = &decl.declarators[0];
3167 let declared_name = init_decl.declarator.name?;
3168 let init = init_decl.init.as_ref()?;
3169
3170 let init_expr = match init {
3172 Initializer::Expr(e) => e.as_ref(),
3173 _ => return None,
3174 };
3175
3176 let last_expr = match &compound.items[1] {
3178 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => e,
3179 _ => return None,
3180 };
3181
3182 if let ExprKind::Ident(name) = &last_expr.kind {
3184 if *name == declared_name {
3185 return Some(init_expr);
3186 }
3187 }
3188
3189 None
3190 }
3191
3192 fn maybe_decay_flex_array(
3203 &self,
3204 access: syn::Expr,
3205 base: &Expr,
3206 member: InternedStr,
3207 info: Option<&MacroInferInfo>,
3208 is_ptr_member: bool,
3209 ) -> syn::Expr {
3210 let Some(fd) = self.fields_dict else { return access; };
3211 let Some(info) = info else { return access; };
3212 let Some(constraints) = info.type_env.expr_constraints.get(&base.id) else {
3213 return access;
3214 };
3215 let Some(base_type) = constraints.first().map(|c| &c.ty) else {
3216 return access;
3217 };
3218 let struct_name = if is_ptr_member {
3219 base_type.pointee_name()
3220 } else {
3221 base_type.type_name()
3222 };
3223 let Some(struct_name) = struct_name else { return access; };
3224 let Some(elem) = fd.flexible_array_element(struct_name, member) else {
3225 return access;
3226 };
3227 let elem_str = elem.to_rust_string(self.interner);
3229 let target_ty_str = format!("*mut {}", elem_str);
3230 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3231 attrs: vec![],
3232 and_token: Default::default(),
3233 raw: Default::default(),
3234 mutability: syn::PointerMutability::Const(Default::default()),
3235 expr: Box::new(access),
3236 });
3237 crate::syn_codegen::insert_cast(raw_const, crate::syn_codegen::parse_type(&target_ty_str))
3238 }
3239
3240 fn try_inline_call_for_addrof(&self, inner: &Expr) -> Option<Expr> {
3249 let (callee_id, args) = match &inner.kind {
3250 ExprKind::Call { func, args } => match &func.kind {
3251 ExprKind::Ident(name) => (*name, args),
3252 _ => return None,
3253 },
3254 _ => return None,
3255 };
3256
3257 let callee_info = self.macro_ctx.macros.get(&callee_id)?;
3258 let body = match &callee_info.parse_result {
3259 ParseResult::Expression(e) => e,
3260 _ => return None,
3261 };
3262
3263 if callee_info.is_thx_dependent {
3265 return None;
3266 }
3267 if callee_info.params.len() != args.len() {
3268 return None;
3269 }
3270
3271 let mut subs: HashMap<InternedStr, &Expr> = HashMap::new();
3273 for (param, arg) in callee_info.params.iter().zip(args.iter()) {
3274 subs.insert(param.name, arg);
3275 }
3276
3277 let mut inlined = (**body).clone();
3278 substitute_idents(&mut inlined, &subs);
3279 Some(inlined)
3280 }
3281
3282 fn build_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
3287 use crate::syn_codegen::*;
3288
3289 match &expr.kind {
3290 ExprKind::Ident(name) => {
3291 if let Some(subst) = self.param_substitutions.get(name) {
3293 return syn::parse_str(subst).unwrap_or_else(|_| int_lit(0));
3295 }
3296 let name_str = self.interner.get(*name);
3297 if LIBC_FUNCTIONS.contains(&name_str) {
3299 self.used_libc_fns.insert(name_str.to_string());
3300 }
3301 if !self.current_local_names.contains(name)
3303 && !self.enum_dict.is_enum_variant(*name)
3304 && !self.known_symbols.contains(name_str)
3305 {
3306 let s = name_str.to_string();
3307 if !self.unresolved_names.contains(&s) {
3308 self.unresolved_names.push(s);
3309 }
3310 }
3311 if name_str == "true" || name_str == "false" {
3313 return syn::Expr::Lit(syn::ExprLit {
3314 attrs: vec![],
3315 lit: syn::Lit::Bool(syn::LitBool {
3316 value: name_str == "true",
3317 span: proc_macro2::Span::call_site(),
3318 }),
3319 });
3320 }
3321 let escaped = escape_rust_keyword(name_str);
3322 if self.bindings_info.static_arrays.contains(name_str) {
3337 let elem = self.bindings_info.static_array_element_type(name_str)
3338 .unwrap_or_else(|| "u8".to_string());
3339 return syn::parse_str(&format!(
3340 "((&raw const {}) as *const {})",
3341 escaped, elem
3342 ))
3343 .unwrap_or_else(|_| int_lit(0));
3344 }
3345 syn::Expr::Path(syn::ExprPath {
3346 attrs: vec![],
3347 qself: None,
3348 path: ident(&escaped).into(),
3349 })
3350 }
3351 ExprKind::IntLit(n) => int_lit(*n),
3352 ExprKind::UIntLit(n) => {
3353 let lit = syn::LitInt::new(&format!("{}u64", n), proc_macro2::Span::call_site());
3354 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Int(lit) })
3355 }
3356 ExprKind::FloatLit(f) => {
3357 let lit = syn::LitFloat::new(&format!("{}", f), proc_macro2::Span::call_site());
3358 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Float(lit) })
3359 }
3360 ExprKind::CharLit(c) => {
3361 let s = if c.is_ascii() {
3362 format!("b'{}' as i8", escape_char(*c))
3363 } else {
3364 format!("0x{:02x}u8 as i8", c)
3365 };
3366 syn::parse_str(&s).unwrap_or_else(|_| int_lit(0))
3367 }
3368 ExprKind::StringLit(s) => {
3369 syn::parse_str(&format!("c\"{}\"", escape_string(s)))
3370 .unwrap_or_else(|_| int_lit(0))
3371 }
3372 ExprKind::Deref(inner) => {
3373 let e = self.build_syn_expr(inner, info);
3374 deref(e)
3375 }
3376 ExprKind::AddrOf(inner) => {
3377 if let Some(inlined) = self.try_inline_call_for_addrof(inner) {
3383 let e = self.build_syn_expr(&inlined, info);
3384 return addr_of_mut(e);
3385 }
3386 let e = self.build_syn_expr(inner, info);
3387 addr_of_mut(e)
3388 }
3389 ExprKind::UnaryPlus(inner) => {
3390 self.build_syn_expr(inner, info)
3391 }
3392 ExprKind::BitNot(inner) => {
3393 let e = self.build_syn_expr(inner, info);
3394 syn::Expr::Unary(syn::ExprUnary {
3395 attrs: vec![],
3396 op: syn::UnOp::Not(Default::default()),
3397 expr: Box::new(e),
3398 })
3399 }
3400 ExprKind::Member { expr: base, member } => {
3401 let e = self.build_syn_expr(base, info);
3402 let m = self.interner.get(*member);
3403 if self.is_bitfield_method(m) {
3404 syn::Expr::MethodCall(syn::ExprMethodCall {
3406 attrs: vec![],
3407 receiver: Box::new(e),
3408 dot_token: Default::default(),
3409 method: ident(m),
3410 turbofish: None,
3411 paren_token: Default::default(),
3412 args: syn::punctuated::Punctuated::new(),
3413 })
3414 } else {
3415 let access = field_access(e, m);
3416 self.maybe_decay_flex_array(access, base, *member, info, false)
3417 }
3418 }
3419 ExprKind::PtrMember { expr: base, member } => {
3420 let e = self.build_syn_expr(base, info);
3421 let m = self.interner.get(*member);
3422 let derefed = deref(e);
3423 if self.is_bitfield_method(m) {
3424 syn::Expr::MethodCall(syn::ExprMethodCall {
3425 attrs: vec![],
3426 receiver: Box::new(derefed),
3427 dot_token: Default::default(),
3428 method: ident(m),
3429 turbofish: None,
3430 paren_token: Default::default(),
3431 args: syn::punctuated::Punctuated::new(),
3432 })
3433 } else {
3434 let access = field_access(derefed, m);
3435 self.maybe_decay_flex_array(access, base, *member, info, true)
3436 }
3437 }
3438 ExprKind::Comma { lhs, rhs } => {
3439 let l = self.build_syn_expr(lhs, info);
3440 let r = self.build_syn_expr(rhs, info);
3441 if expr_yields_value_for_stmt_use(&l) {
3453 let l_str = expr_to_string(&l);
3454 let r_str = expr_to_string(&r);
3455 syn::parse_str(&format!("{{ let _ = {}; {} }}", l_str, r_str))
3456 .unwrap_or_else(|_| int_lit(0))
3457 } else {
3458 syn::Expr::Block(syn::ExprBlock {
3459 attrs: vec![],
3460 label: None,
3461 block: syn::Block {
3462 brace_token: Default::default(),
3463 stmts: vec![
3464 syn::Stmt::Expr(l, Some(Default::default())),
3465 syn::Stmt::Expr(r, None),
3466 ],
3467 },
3468 })
3469 }
3470 }
3471 ExprKind::UnaryMinus(inner) => {
3472 let e = self.build_syn_expr(inner, info);
3473 let e_str = expr_to_string(&e);
3475 if is_unsigned_cast_expr(&e_str) {
3476 return syn::parse_str(&format!("({}).wrapping_neg()", e_str.trim_start_matches('-')))
3477 .unwrap_or_else(|_| int_lit(0));
3478 }
3479 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
3480 let ts = ut.to_rust_string();
3481 if matches!(normalize_integer_type(&ts), Some("usize" | "u8" | "u16" | "u32" | "u64")) {
3482 self.codegen_errors.push(format!("cannot negate unsigned type: -({}: {})", e_str, ts));
3483 }
3484 }
3485 syn::Expr::Unary(syn::ExprUnary {
3486 attrs: vec![],
3487 op: syn::UnOp::Neg(Default::default()),
3488 expr: Box::new(e),
3489 })
3490 }
3491 ExprKind::LogNot(inner) => {
3492 if matches!(&inner.kind, ExprKind::StringLit(_)) {
3494 return syn::parse_str("false").unwrap_or_else(|_| int_lit(0));
3495 }
3496 let e = self.build_syn_expr(inner, info);
3497 let bool_e = if self.is_bool_expr_with_dict(inner) {
3498 e
3499 } else if self.is_pointer_expr_unified(inner, info)
3500 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()) {
3501 syn::Expr::MethodCall(syn::ExprMethodCall {
3503 attrs: vec![],
3504 receiver: Box::new(e),
3505 dot_token: Default::default(),
3506 method: ident("is_null"),
3507 turbofish: None,
3508 paren_token: Default::default(),
3509 args: syn::punctuated::Punctuated::new(),
3510 })
3511 } else {
3512 wrap_as_bool(e)
3514 };
3515 syn::Expr::Unary(syn::ExprUnary {
3516 attrs: vec![],
3517 op: syn::UnOp::Not(Default::default()),
3518 expr: Box::new(bool_e),
3519 })
3520 }
3521 ExprKind::Cast { type_name, expr: inner } => {
3522 let t = self.type_name_to_rust(type_name);
3523 if is_unsigned_integer_target(&t) {
3527 if let ExprKind::UnaryMinus(minus_inner) = &inner.kind {
3528 if matches!(&minus_inner.kind,
3529 ExprKind::IntLit(1) | ExprKind::UIntLit(1))
3530 {
3531 return syn::parse_str(&format!("{}::MAX", t))
3532 .unwrap_or_else(|_| int_lit(0));
3533 }
3534 }
3535 }
3536 if (t.starts_with("*mut ") || t.starts_with("*const "))
3543 && matches!(&inner.kind, ExprKind::AddrOf(_))
3544 {
3545 if let ExprKind::AddrOf(addrof_inner) = &inner.kind {
3546 let inlined_owned;
3548 let inner_to_build: &Expr =
3549 if let Some(inlined) = self.try_inline_call_for_addrof(addrof_inner) {
3550 inlined_owned = inlined;
3551 &inlined_owned
3552 } else {
3553 addrof_inner
3554 };
3555 let inner_e = self.build_syn_expr(inner_to_build, info);
3556 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3557 attrs: vec![],
3558 and_token: Default::default(),
3559 raw: Default::default(),
3560 mutability: syn::PointerMutability::Const(Default::default()),
3561 expr: Box::new(inner_e),
3562 });
3563 return insert_cast(raw_const, parse_type(&t));
3564 }
3565 }
3566 let e = self.build_syn_expr(inner, info);
3567 if t == "()" {
3568 let e_str = expr_to_string(&e);
3575 return syn::parse_str(&format!("{{ let _ = {}; }}", e_str))
3576 .unwrap_or_else(|_| int_lit(0));
3577 }
3578 if t == "bool" {
3579 if self.is_bool_expr_with_dict(inner) {
3581 return e;
3582 }
3583 if self.is_pointer_expr_unified(inner, info)
3584 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()) {
3585 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3587 attrs: vec![],
3588 receiver: Box::new(e),
3589 dot_token: Default::default(),
3590 method: ident("is_null"),
3591 turbofish: None,
3592 paren_token: Default::default(),
3593 args: syn::punctuated::Punctuated::new(),
3594 });
3595 return syn::Expr::Unary(syn::ExprUnary {
3596 attrs: vec![],
3597 op: syn::UnOp::Not(Default::default()),
3598 expr: Box::new(is_null),
3599 });
3600 }
3601 return wrap_as_bool(e);
3602 }
3603 if self.is_enum_cast_target(type_name) {
3604 let e_str = expr_to_string(&e);
3606 return syn::parse_str(&format!("std::mem::transmute::<_, {}>({})", t, e_str))
3607 .unwrap_or_else(|_| int_lit(0));
3608 }
3609 insert_cast(e, parse_type(&t))
3610 }
3611 ExprKind::Sizeof(inner) => {
3612 if let ExprKind::Ident(name) = &inner.kind {
3614 if self.current_literal_string_params.contains(name) {
3615 let param = escape_rust_keyword(self.interner.get(*name));
3616 return syn::parse_str(&format!("({}.len() + 1)", param))
3617 .unwrap_or_else(|_| int_lit(0));
3618 }
3619 }
3620 let e = self.build_syn_expr(inner, info);
3621 let e_str = expr_to_string(&e);
3622 syn::parse_str(&format!("std::mem::size_of_val(&({}))", e_str))
3627 .unwrap_or_else(|_| int_lit(0))
3628 }
3629 ExprKind::SizeofType(type_name) => {
3630 let t = self.type_name_to_rust(type_name);
3631 syn::parse_str(&format!("std::mem::size_of::<{}>()", t))
3632 .unwrap_or_else(|_| int_lit(0))
3633 }
3634 ExprKind::Index { expr: base, index } => {
3635 use crate::syn_codegen::*;
3636 let i = self.build_syn_expr(index, info);
3637 let i_isize = cast_syn_expr(i, "isize");
3638 let base_expr: syn::Expr = if self.is_array_like_expr(base, info) {
3639 let raw_ptr_expr: syn::Expr = if let ExprKind::Ident(n) = &base.kind {
3645 let name_str = self.interner.get(*n);
3646 let escaped = escape_rust_keyword(name_str);
3647 if self.bindings_info.static_arrays.contains(name_str) {
3648 let elem = self.bindings_info
3649 .static_array_element_type(name_str)
3650 .unwrap_or_else(|| "u8".to_string());
3651 syn::parse_str(&format!(
3652 "((&raw const {}) as *const {})",
3653 escaped, elem
3654 ))
3655 .unwrap_or_else(|_| int_lit(0))
3656 } else {
3657 let id = ident_expr(escaped.as_str());
3658 method_call(id, "as_ptr", vec![])
3659 }
3660 } else {
3661 let b = self.build_syn_expr(base, info);
3662 method_call(b, "as_ptr", vec![])
3663 };
3664 let elem_str = self.infer_expr_type_unified(base, info)
3668 .and_then(|ut| ut.inner_type().cloned())
3669 .map(|inner| inner.to_rust_string());
3670 if let Some(elem) = elem_str {
3671 cast_syn_expr(raw_ptr_expr, &format!("*mut {}", elem))
3672 } else {
3673 raw_ptr_expr
3674 }
3675 } else {
3676 self.build_syn_expr(base, info)
3677 };
3678 let offset_call = method_call(base_expr, "offset", vec![i_isize]);
3679 deref(offset_call)
3680 }
3681 ExprKind::Conditional { cond, then_expr, else_expr } => {
3682 let c = self.build_syn_expr(cond, info);
3683 let c_str = expr_to_string(&c);
3684 let cond_str = self.wrap_as_bool_condition(cond, &c_str, info);
3685 let cond_syn: syn::Expr = syn::parse_str(&cond_str).unwrap_or(c);
3686
3687 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
3688 let tt = self.infer_expr_type_unified(then_expr, info);
3689 let et = self.infer_expr_type_unified(else_expr, info);
3690
3691 if let Some(ref hint) = type_hint {
3693 let hint_ut = UnifiedType::from_rust_str(hint);
3694 if hint_ut.is_pointer() {
3695 if is_null_literal(else_expr) {
3696 let t = self.build_syn_expr(then_expr, info);
3697 let e: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3698 .unwrap_or_else(|_| int_lit(0));
3699 return if_else(cond_syn, t, e);
3700 }
3701 if is_null_literal(then_expr) {
3702 let t: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3703 .unwrap_or_else(|_| int_lit(0));
3704 let e = self.build_syn_expr(else_expr, info);
3705 return if_else(cond_syn, t, e);
3706 }
3707 }
3708 if normalize_integer_type(hint).is_some() {
3711 if is_null_literal(else_expr) {
3712 let t = self.build_syn_expr(then_expr, info);
3713 return if_else(cond_syn, t, int_lit(0));
3714 }
3715 if is_null_literal(then_expr) {
3716 let e = self.build_syn_expr(else_expr, info);
3717 return if_else(cond_syn, int_lit(0), e);
3718 }
3719 }
3720 if hint_ut.is_bool() {
3721 let then_syn = match &then_expr.kind {
3722 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3723 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3724 _ => self.build_syn_expr(then_expr, info),
3725 };
3726 let else_syn = match &else_expr.kind {
3727 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3728 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3729 _ => self.build_syn_expr(else_expr, info),
3730 };
3731 return if_else(cond_syn, then_syn, else_syn);
3732 }
3733 }
3734
3735 let then_syn = if is_null_literal(then_expr) {
3737 if let Some(ref eut) = et {
3738 if eut.is_pointer() {
3739 syn::parse_str(&null_ptr_expr(eut)).unwrap_or_else(|_| int_lit(0))
3740 } else { self.build_syn_expr(then_expr, info) }
3741 } else { self.build_syn_expr(then_expr, info) }
3742 } else { self.build_syn_expr(then_expr, info) };
3743
3744 let else_syn = if is_null_literal(else_expr) {
3745 if let Some(ref tut) = tt {
3746 if tut.is_pointer() {
3747 syn::parse_str(&null_ptr_expr(tut)).unwrap_or_else(|_| int_lit(0))
3748 } else { self.build_syn_expr(else_expr, info) }
3749 } else { self.build_syn_expr(else_expr, info) }
3750 } else { self.build_syn_expr(else_expr, info) };
3751
3752 if let (Some(tut), Some(eut)) = (&tt, &et) {
3754 let ts = tut.to_rust_string();
3755 let es = eut.to_rust_string();
3756 if let (Some(tn), Some(en)) = (normalize_integer_type(&ts), normalize_integer_type(&es)) {
3757 if tn != en {
3758 if let Some(wider) = wider_integer_type(&ts, &es) {
3759 let (then_final, else_final) = if normalize_integer_type(&ts) != Some(wider) {
3760 (cast_syn_expr(then_syn, wider), else_syn)
3761 } else {
3762 (then_syn, cast_syn_expr(else_syn, wider))
3763 };
3764 return if_else(cond_syn, then_final, else_final);
3765 }
3766 }
3767 }
3768 if tut.is_pointer() && eut.is_pointer() && ts != es
3771 && is_sv_subtype_cast(tut, eut)
3772 {
3773 let target_str = type_hint.as_deref()
3776 .filter(|t| *t != "()" && !UnifiedType::from_rust_str(t).is_void())
3777 .unwrap_or(&ts)
3778 .to_string();
3779 return if_else(
3780 cond_syn,
3781 cast_syn_expr(then_syn, &target_str),
3782 cast_syn_expr(else_syn, &target_str),
3783 );
3784 }
3785 }
3786
3787 if_else(cond_syn, then_syn, else_syn)
3788 }
3789 ExprKind::Binary { op, lhs, rhs } => {
3790 if *op == BinOp::Sub {
3792 if let ExprKind::Sizeof(inner) = &lhs.kind {
3793 if let ExprKind::Ident(name) = &inner.kind {
3794 if self.current_literal_string_params.contains(name) {
3795 if let ExprKind::IntLit(1) = &rhs.kind {
3796 let param = escape_rust_keyword(self.interner.get(*name));
3797 return syn::parse_str(&format!("{}.len()", param))
3798 .unwrap_or_else(|_| int_lit(0));
3799 }
3800 }
3801 }
3802 }
3803 }
3804
3805 if matches!(op, BinOp::Eq | BinOp::Ne) {
3808 let s_eq = |s: &ExprKind| matches!(s, ExprKind::StringLit(_));
3809 let lhs_is_str = s_eq(&lhs.kind);
3810 let rhs_is_str = s_eq(&rhs.kind);
3811 if (lhs_is_str && is_null_literal(rhs))
3812 || (rhs_is_str && is_null_literal(lhs))
3813 {
3814 return syn::parse_str(
3815 if *op == BinOp::Eq { "false" } else { "true" }
3816 ).unwrap_or_else(|_| int_lit(0));
3817 }
3818 }
3819 if matches!(op, BinOp::Eq | BinOp::Ne) {
3823 let opt_lhs = (is_null_literal(rhs) || matches!(&rhs.kind, ExprKind::IntLit(0)))
3824 && self.is_option_fn_pointer_expr(lhs, info);
3825 let opt_rhs = (is_null_literal(lhs) || matches!(&lhs.kind, ExprKind::IntLit(0)))
3826 && self.is_option_fn_pointer_expr(rhs, info);
3827 if opt_lhs || opt_rhs {
3828 let receiver_expr = if opt_lhs { lhs } else { rhs };
3829 let r = self.build_syn_expr(receiver_expr, info);
3830 let method = if *op == BinOp::Eq { "is_none" } else { "is_some" };
3831 return syn::Expr::MethodCall(syn::ExprMethodCall {
3832 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3833 method: ident(method), turbofish: None,
3834 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3835 });
3836 }
3837 }
3838 if matches!(op, BinOp::Eq | BinOp::Ne) {
3840 if is_null_literal(rhs) {
3841 if self.is_pointer_expr_unified(lhs, info)
3842 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer()) {
3843 let l = self.build_syn_expr(lhs, info);
3844 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3845 attrs: vec![], receiver: Box::new(l), dot_token: Default::default(),
3846 method: ident("is_null"), turbofish: None,
3847 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3848 });
3849 return if *op == BinOp::Eq { is_null } else {
3850 syn::Expr::Unary(syn::ExprUnary {
3851 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3852 expr: Box::new(is_null),
3853 })
3854 };
3855 }
3856 }
3857 if is_null_literal(lhs) {
3858 if self.is_pointer_expr_unified(rhs, info)
3859 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer()) {
3860 let r = self.build_syn_expr(rhs, info);
3861 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3862 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3863 method: ident("is_null"), turbofish: None,
3864 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3865 });
3866 return if *op == BinOp::Eq { is_null } else {
3867 syn::Expr::Unary(syn::ExprUnary {
3868 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3869 expr: Box::new(is_null),
3870 })
3871 };
3872 }
3873 }
3874 if self.is_bool_expr_with_dict(lhs) {
3876 match (&rhs.kind, op) {
3877 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
3878 return self.build_syn_expr(lhs, info);
3879 }
3880 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
3881 let l = self.build_syn_expr(lhs, info);
3882 return syn::Expr::Unary(syn::ExprUnary {
3883 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3884 expr: Box::new(l),
3885 });
3886 }
3887 _ => {}
3888 }
3889 }
3890 if self.is_bool_expr_with_dict(rhs) {
3891 match (&lhs.kind, op) {
3892 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
3893 return self.build_syn_expr(rhs, info);
3894 }
3895 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
3896 let r = self.build_syn_expr(rhs, info);
3897 return syn::Expr::Unary(syn::ExprUnary {
3898 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3899 expr: Box::new(r),
3900 });
3901 }
3902 _ => {}
3903 }
3904 }
3905 }
3906
3907 if matches!(op, BinOp::Add | BinOp::Sub) {
3909 let l_arr = !self.is_static_array_expr(lhs)
3914 && self.is_array_like_expr(lhs, info);
3915 let r_arr = !self.is_static_array_expr(rhs)
3916 && self.is_array_like_expr(rhs, info);
3917 let lp = l_arr
3918 || self.is_static_array_expr(lhs)
3919 || self.is_pointer_expr_unified(lhs, info)
3920 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
3921 let rp = r_arr
3922 || self.is_static_array_expr(rhs)
3923 || self.is_pointer_expr_unified(rhs, info)
3924 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
3925 let l_is_static_arr = self.is_static_array_expr(lhs);
3932 let r_is_static_arr = self.is_static_array_expr(rhs);
3933 let cast_to_mut = |this: &mut Self, expr: syn::Expr, arr_expr: &Expr,
3934 needs_as_ptr: bool| -> syn::Expr {
3935 let elem = this.infer_expr_type_unified(arr_expr, info)
3936 .and_then(|ut| ut.inner_type().cloned())
3937 .map(|u| u.to_rust_string());
3938 let base = if needs_as_ptr {
3939 crate::syn_codegen::method_call(expr, "as_ptr", vec![])
3940 } else {
3941 expr
3942 };
3943 if let Some(e) = elem {
3944 crate::syn_codegen::cast_syn_expr(base, &format!("*mut {}", e))
3945 } else {
3946 base
3947 }
3948 };
3949 if lp && !rp {
3950 let l = self.build_syn_expr(lhs, info);
3951 let l = if l_arr {
3952 cast_to_mut(self, l, lhs, true)
3953 } else if l_is_static_arr {
3954 cast_to_mut(self, l, lhs, false)
3955 } else {
3956 l
3957 };
3958 let r = self.build_syn_expr(rhs, info);
3959 let r_isize = crate::syn_codegen::cast_syn_expr(r, "isize");
3960 let arg = if *op == BinOp::Add { r_isize } else {
3961 syn::Expr::Unary(syn::ExprUnary {
3962 attrs: vec![],
3963 op: syn::UnOp::Neg(Default::default()),
3964 expr: Box::new(r_isize),
3965 })
3966 };
3967 return crate::syn_codegen::method_call(l, "offset", vec![arg]);
3968 }
3969 if rp && !lp && *op == BinOp::Add {
3970 let l = self.build_syn_expr(lhs, info);
3971 let r = self.build_syn_expr(rhs, info);
3972 let r = if r_arr {
3973 cast_to_mut(self, r, rhs, true)
3974 } else if r_is_static_arr {
3975 cast_to_mut(self, r, rhs, false)
3976 } else {
3977 r
3978 };
3979 let l_isize = crate::syn_codegen::cast_syn_expr(l, "isize");
3980 return crate::syn_codegen::method_call(r, "offset", vec![l_isize]);
3981 }
3982 if lp && rp && *op == BinOp::Sub {
3983 let l = self.build_syn_expr(lhs, info);
3984 let r = self.build_syn_expr(rhs, info);
3985 return crate::syn_codegen::method_call(l, "offset_from", vec![r]);
3986 }
3987 }
3988
3989 if matches!(&rhs.kind, ExprKind::IntLit(_)) {
3991 if let Some(lut) = self.infer_expr_type_unified(lhs, info) {
3992 if lut.is_float() {
3993 if let ExprKind::IntLit(v) = &rhs.kind {
3994 let l = self.build_syn_expr(lhs, info);
3995 let l_str = expr_to_string(&l);
3996 return syn::parse_str(&format!("{} {} {}.0", l_str, bin_op_to_rust(*op), v))
3997 .unwrap_or_else(|_| int_lit(0));
3998 }
3999 }
4000 }
4001 }
4002 if matches!(&lhs.kind, ExprKind::IntLit(_)) {
4003 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4004 if rut.is_float() {
4005 if let ExprKind::IntLit(v) = &lhs.kind {
4006 let r = self.build_syn_expr(rhs, info);
4007 let r_str = expr_to_string(&r);
4008 return syn::parse_str(&format!("{}.0 {} {}", v, bin_op_to_rust(*op), r_str))
4009 .unwrap_or_else(|_| int_lit(0));
4010 }
4011 }
4012 }
4013 }
4014
4015 if matches!(op, BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Eq | BinOp::Ne) {
4020 if let (Some(lut), Some(rut)) =
4021 (self.infer_expr_type_unified(lhs, info),
4022 self.infer_expr_type_unified(rhs, info))
4023 {
4024 if lut.is_pointer() && rut.is_pointer()
4025 && pointer_inner_compatible(&lut, &rut)
4026 && (lut.is_const_pointer() != rut.is_const_pointer()
4027 || lut.to_rust_string() != rut.to_rust_string())
4028 {
4029 let l = self.build_syn_expr(lhs, info);
4030 let r = self.build_syn_expr(rhs, info);
4031 let target = lut.to_rust_string();
4032 return syn::Expr::Binary(syn::ExprBinary {
4033 attrs: vec![], left: Box::new(l),
4034 op: crate::syn_codegen::to_syn_binop(*op),
4035 right: Box::new(crate::syn_codegen::cast_syn_expr(r, &target)),
4036 });
4037 }
4038 }
4039 }
4040
4041 let l = self.build_syn_expr(lhs, info);
4042 let r = self.build_syn_expr(rhs, info);
4043
4044 if matches!(op, BinOp::LogAnd | BinOp::LogOr) {
4046 let l_str = expr_to_string(&l);
4047 let r_str = expr_to_string(&r);
4048 let l_bool = self.wrap_as_bool_condition(lhs, &l_str, info);
4049 let r_bool = self.wrap_as_bool_condition(rhs, &r_str, info);
4050 let l_syn: syn::Expr = syn::parse_str(&l_bool).unwrap_or(l);
4051 let r_syn: syn::Expr = syn::parse_str(&r_bool).unwrap_or(r);
4052 return syn::Expr::Binary(syn::ExprBinary {
4053 attrs: vec![], left: Box::new(l_syn),
4054 op: crate::syn_codegen::to_syn_binop(*op),
4055 right: Box::new(r_syn),
4056 });
4057 }
4058
4059 let lt = self.infer_expr_type_unified(lhs, info);
4061 let rt = self.infer_expr_type_unified(rhs, info);
4062
4063 let make_binary_op = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4067 syn::Expr::Binary(syn::ExprBinary {
4068 attrs: vec![], left: Box::new(left),
4069 op: crate::syn_codegen::to_syn_binop(*op),
4070 right: Box::new(right),
4071 })
4072 };
4073 match (<, &rt) {
4074 (Some(lut), None) if self.is_rust_enum_type(lut) => {
4075 return make_binary_op(cast_syn_expr(l, "u32"), r);
4076 }
4077 (None, Some(rut)) if self.is_rust_enum_type(rut) => {
4078 return make_binary_op(l, cast_syn_expr(r, "u32"));
4079 }
4080 _ => {}
4081 }
4082
4083 if let (Some(lut), Some(rut)) = (<, &rt) {
4084 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4085 syn::Expr::Binary(syn::ExprBinary {
4086 attrs: vec![], left: Box::new(left),
4087 op: crate::syn_codegen::to_syn_binop(*op),
4088 right: Box::new(right),
4089 })
4090 };
4091 let l_is_enum = self.is_rust_enum_type(lut);
4094 let r_is_enum = self.is_rust_enum_type(rut);
4095 if l_is_enum && !r_is_enum {
4096 let rs = rut.to_rust_string();
4097 let target = normalize_integer_type(&rs).unwrap_or("u32");
4098 return make_binary(cast_syn_expr(l, target), r);
4099 }
4100 if r_is_enum && !l_is_enum {
4101 let ls = lut.to_rust_string();
4102 let target = normalize_integer_type(&ls).unwrap_or("u32");
4103 return make_binary(l, cast_syn_expr(r, target));
4104 }
4105 if rut.is_bool() {
4107 let ls = lut.to_rust_string();
4108 if let Some(nl) = normalize_integer_type(&ls) {
4109 return make_binary(l, cast_syn_expr(r, nl));
4110 }
4111 }
4112 if lut.is_bool() {
4113 let rs = rut.to_rust_string();
4114 if let Some(nr) = normalize_integer_type(&rs) {
4115 return make_binary(cast_syn_expr(l, nr), r);
4116 }
4117 }
4118 if lut.is_float() && !rut.is_float() {
4120 let ls = lut.to_rust_string();
4121 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4122 return make_binary(l, cast_syn_expr(r, float_ty));
4123 }
4124 if rut.is_float() && !lut.is_float() {
4125 let rs = rut.to_rust_string();
4126 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4127 return make_binary(cast_syn_expr(l, float_ty), r);
4128 }
4129 let ls = lut.to_rust_string();
4131 let rs = rut.to_rust_string();
4132 if let Some(wider) = wider_integer_type(&ls, &rs) {
4133 if normalize_integer_type(&ls) != Some(wider) {
4134 return make_binary(cast_syn_expr(l, wider), r);
4135 } else {
4136 return make_binary(l, cast_syn_expr(r, wider));
4137 }
4138 }
4139 }
4140 {
4142 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4143 syn::Expr::Binary(syn::ExprBinary {
4144 attrs: vec![], left: Box::new(left),
4145 op: crate::syn_codegen::to_syn_binop(*op),
4146 right: Box::new(right),
4147 })
4148 };
4149 match (<, &rt) {
4150 (Some(lut), None) if lut.is_float() => {
4151 let ls = lut.to_rust_string();
4152 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4153 return make_binary(l, cast_syn_expr(r, float_ty));
4154 }
4155 (None, Some(rut)) if rut.is_float() => {
4156 let rs = rut.to_rust_string();
4157 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4158 return make_binary(cast_syn_expr(l, float_ty), r);
4159 }
4160 _ => {}
4161 }
4162 if matches!(op, BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor) {
4164 match (<, &rt) {
4165 (Some(lut), None) => {
4166 let ls = lut.to_rust_string();
4167 if let Some(nl) = normalize_integer_type(&ls) {
4168 return make_binary(l, cast_syn_expr(r, nl));
4169 }
4170 }
4171 (None, Some(rut)) => {
4172 let rs = rut.to_rust_string();
4173 if let Some(nr) = normalize_integer_type(&rs) {
4174 return make_binary(cast_syn_expr(l, nr), r);
4175 }
4176 }
4177 _ => {}
4178 }
4179 }
4180 }
4181 syn::Expr::Binary(syn::ExprBinary {
4183 attrs: vec![],
4184 left: Box::new(l),
4185 op: crate::syn_codegen::to_syn_binop(*op),
4186 right: Box::new(r),
4187 })
4188 }
4189 ExprKind::Call { func, args } => {
4190 if let Some(syn_call) = self.try_build_common_macro_fn_call(func, args, info) {
4194 return syn_call;
4195 }
4196 if let ExprKind::Ident(name) = &func.kind {
4198 let func_name = self.interner.get(*name);
4199 if func_name == "__builtin_expect" && !args.is_empty() {
4201 return self.build_syn_expr(&args[0], info);
4202 }
4203 if func_name == "__builtin_unreachable" {
4205 return syn::parse_str("std::hint::unreachable_unchecked()").unwrap();
4206 }
4207 if (func_name == "__builtin_ctz" || func_name == "__builtin_ctzl") && args.len() == 1 {
4209 let arg = self.build_syn_expr(&args[0], info);
4210 return syn::Expr::MethodCall(syn::ExprMethodCall {
4211 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4212 method: ident("trailing_zeros"), turbofish: None,
4213 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4214 });
4215 }
4216 if (func_name == "__builtin_clz" || func_name == "__builtin_clzl") && args.len() == 1 {
4217 let arg = self.build_syn_expr(&args[0], info);
4218 return syn::Expr::MethodCall(syn::ExprMethodCall {
4219 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4220 method: ident("leading_zeros"), turbofish: None,
4221 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4222 });
4223 }
4224 if matches!(func_name, "ASSERT_IS_LITERAL" | "ASSERT_IS_PTR" | "ASSERT_NOT_PTR")
4226 && args.len() == 1
4227 {
4228 return self.build_syn_expr(&args[0], info);
4229 }
4230 if matches!(func_name, "offsetof" | "__builtin_offsetof") && args.len() == 2 {
4239 let type_name_str = if let ExprKind::Ident(name) = &args[0].kind {
4240 escape_rust_keyword(self.interner.get(*name)).to_string()
4241 } else {
4242 let s = self.build_syn_expr(&args[0], info);
4243 expr_to_string(&s)
4244 };
4245 if let Some(field_path) = self.expr_to_field_path(&args[1]) {
4246 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_name_str, field_path))
4247 .unwrap_or_else(|_| int_lit(0));
4248 }
4249 }
4250 }
4251
4252 let f_syn = self.build_syn_expr(func, info);
4254 let f_str = expr_to_string(&f_syn);
4255
4256 let callee_name = if let ExprKind::Ident(name) = &func.kind { Some(*name) } else { None };
4257 let needs_my_perl = callee_name
4258 .map(|name| self.needs_my_perl_for_call(name, args.len()))
4259 .unwrap_or(false);
4260
4261 let callee_generics = callee_name
4263 .and_then(|name| self.get_callee_generic_params(name).cloned());
4264
4265 if let Some(ref generics) = callee_generics {
4266 let mut type_args = Vec::new();
4268 let mut value_args: Vec<String> = if needs_my_perl {
4269 vec!["my_perl".to_string()]
4270 } else { vec![] };
4271 let mut value_idx = if needs_my_perl { 1usize } else { 0 };
4272 for (i, arg) in args.iter().enumerate() {
4273 if generics.contains_key(&(i as i32)) {
4274 let syn_arg = self.build_syn_expr(arg, info);
4275 type_args.push(normalize_parens(&expr_to_string(&syn_arg)));
4276 } else {
4277 value_args.push(self.build_arg_string_unified(arg, info, callee_name, value_idx));
4278 value_idx += 1;
4279 }
4280 }
4281 return syn::parse_str(&format!("{}::<{}>({})", f_str, type_args.join(", "), value_args.join(", ")))
4282 .unwrap_or_else(|_| int_lit(0));
4283 }
4284
4285 let mut arg_strs: Vec<String> = if needs_my_perl {
4287 vec!["my_perl".to_string()]
4288 } else { vec![] };
4289 let arg_offset = if needs_my_perl { 1usize } else { 0 };
4290 for (i, arg) in args.iter().enumerate() {
4291 arg_strs.push(self.build_arg_string_unified(arg, info, callee_name, i + arg_offset));
4292 }
4293 syn::parse_str(&format!("{}({})", f_str, arg_strs.join(", ")))
4294 .unwrap_or_else(|_| int_lit(0))
4295 }
4296 ExprKind::MacroCall { name, args, expanded, .. } => {
4297 if self.should_emit_as_macro_call(*name) {
4298 let name_str = escape_rust_keyword(self.interner.get(*name));
4299 let needs_my_perl = self.needs_my_perl_for_call(*name, args.len());
4300 let mut a: Vec<String> = if needs_my_perl {
4301 vec!["my_perl".to_string()]
4302 } else { vec![] };
4303 for arg in args {
4304 let arg_str = expr_to_string(&self.build_syn_expr(arg, info));
4305 a.push(normalize_parens(&arg_str));
4306 }
4307 syn::parse_str(&format!("{}({})", name_str, a.join(", ")))
4308 .unwrap_or_else(|_| int_lit(0))
4309 } else {
4310 self.build_syn_expr(expanded, info)
4311 }
4312 }
4313 ExprKind::BuiltinCall { name, args } => {
4314 let func_name = self.interner.get(*name);
4315 if matches!(func_name, "offsetof" | "__builtin_offsetof" | "STRUCT_OFFSET")
4316 && args.len() == 2
4317 {
4318 let type_str = match &args[0] {
4319 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4320 crate::ast::BuiltinArg::Expr(e) => {
4321 let s = self.build_syn_expr(e, info);
4322 expr_to_string(&s)
4323 }
4324 };
4325 let field_expr = match &args[1] {
4326 crate::ast::BuiltinArg::Expr(e) => self.expr_to_field_path(e),
4327 _ => None,
4328 };
4329 if let Some(fp) = field_expr {
4330 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_str, fp))
4331 .unwrap_or_else(|_| int_lit(0));
4332 }
4333 }
4334 let a: Vec<String> = args.iter().map(|arg| match arg {
4336 crate::ast::BuiltinArg::Expr(e) => {
4337 let s = self.build_syn_expr(e, info);
4338 expr_to_string(&s)
4339 }
4340 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4341 }).collect();
4342 syn::parse_str(&format!("{}({})", func_name, a.join(", ")))
4343 .unwrap_or_else(|_| int_lit(0))
4344 }
4345 ExprKind::Assign { op, lhs, rhs } => {
4346 self.build_assign_syn_expr(*op, lhs, rhs, info)
4347 }
4348 ExprKind::PreInc(inner) => {
4349 self.build_inc_dec_syn_expr(inner, info, true, false)
4350 }
4351 ExprKind::PreDec(inner) => {
4352 self.build_inc_dec_syn_expr(inner, info, false, false)
4353 }
4354 ExprKind::PostInc(inner) => {
4355 self.build_inc_dec_syn_expr(inner, info, true, true)
4356 }
4357 ExprKind::PostDec(inner) => {
4358 self.build_inc_dec_syn_expr(inner, info, false, true)
4359 }
4360 ExprKind::Assert { kind, condition } => {
4361 let assert_str = if let Some((real_cond, msg)) = decompose_assert_with_message(condition) {
4362 let c = self.build_syn_expr(real_cond, info);
4363 let c_str = expr_to_string(&c);
4364 let cond_str = self.wrap_as_bool_condition(real_cond, &c_str, info);
4365 format!("assert!({}, \"{}\")", normalize_parens(&cond_str), msg)
4366 } else {
4367 let c = self.build_syn_expr(condition, info);
4368 let c_str = expr_to_string(&c);
4369 if is_boolean_expr(condition) || self.is_bool_expr_with_dict(condition) {
4370 format!("assert!({})", normalize_parens(&c_str))
4371 } else if self.is_pointer_expr_unified(condition, info)
4372 || self.infer_expr_type_unified(condition, info).is_some_and(|ut| ut.is_pointer()) {
4373 format!("assert!(!({}).is_null())", c_str)
4377 } else {
4378 format!("assert!({} != 0)", normalize_parens(&c_str))
4379 }
4380 };
4381 let result = match kind {
4382 AssertKind::Assert => assert_str,
4383 AssertKind::AssertUnderscore => format!("{{ {}; }}", assert_str),
4384 };
4385 syn::parse_str(&result).unwrap_or_else(|_| int_lit(0))
4386 }
4387 ExprKind::StmtExpr(compound) => {
4388 if let Some(init_expr) = self.detect_mutable_ptr_pattern(compound) {
4390 return self.build_syn_expr(init_expr, info);
4391 }
4392 let mut parts: Vec<String> = Vec::new();
4396 for item in &compound.items {
4397 match item {
4398 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => {
4399 parts.push(self.build_expr_string(e, info));
4400 }
4401 BlockItem::Stmt(stmt) => {
4402 let s = match info {
4403 Some(info) => self.stmt_to_rust(stmt, info),
4404 None => self.stmt_to_rust_inline(stmt, ""),
4405 };
4406 parts.push(s);
4407 }
4408 BlockItem::Decl(decl) => {
4409 self.collect_decl_types(decl);
4410 let decl_str = self.decl_to_rust_let(decl, "");
4411 for line in decl_str.lines() {
4412 let trimmed = line.trim();
4413 if !trimmed.is_empty() {
4414 parts.push(trimmed.strip_suffix(';').unwrap_or(trimmed).to_string());
4415 }
4416 }
4417 }
4418 }
4419 }
4420 let block_str = if parts.is_empty() {
4421 "{ }".to_string()
4422 } else if parts.len() == 1 {
4423 parts.pop().unwrap()
4424 } else {
4425 let last = parts.pop().unwrap();
4426 let stmts = parts.join("; ");
4427 format!("{{ {}; {} }}", stmts, last)
4428 };
4429 syn::parse_str(&block_str).unwrap_or_else(|_| int_lit(0))
4430 }
4431 ExprKind::Alignof(ty) => {
4432 let ty_str = self.type_name_to_rust(ty);
4433 syn::parse_str(&format!("std::mem::align_of::<{}>()", ty_str))
4434 .unwrap_or_else(|_| int_lit(0))
4435 }
4436 _ => {
4440 self.codegen_errors.push(format!(
4441 "unhandled ExprKind in syn codegen: {:?}",
4442 std::mem::discriminant(&expr.kind)
4443 ));
4444 int_lit(0)
4445 }
4446 }
4447 }
4448
4449 fn build_arg_string_unified(&mut self, arg: &Expr, info: Option<&MacroInferInfo>,
4453 callee: Option<InternedStr>, arg_index: usize) -> String {
4454 if info.is_some() {
4456 if let Some(name) = self.find_literal_string_ident(arg) {
4457 if let Some(callee_name) = callee {
4458 if self.callee_expects_literal_string(callee_name, arg_index) {
4459 return escape_rust_keyword(self.interner.get(*name));
4460 }
4461 }
4462 let param = escape_rust_keyword(self.interner.get(*name));
4463 return format!("{}.as_ptr() as *const c_char", param);
4464 }
4465 }
4466 if is_null_literal(arg) {
4468 if let Some(callee_name) = callee {
4469 let func_name = self.interner.get(callee_name).to_string();
4470 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4471 if expected_ut.is_pointer() {
4472 return null_ptr_expr(&expected_ut);
4473 }
4474 }
4475 }
4476 }
4477 if let Some(callee_name) = callee {
4479 let func_name = self.interner.get(callee_name);
4480 if self.callee_param_is_bool(func_name, arg_index) {
4481 match &arg.kind {
4482 ExprKind::IntLit(0) => return "false".to_string(),
4483 ExprKind::IntLit(1) => return "true".to_string(),
4484 _ => {}
4485 }
4486 }
4487 }
4488 let mut syn_expr = self.build_syn_expr(arg, info);
4490 if let Some(callee_name) = callee {
4493 let func_name = self.interner.get(callee_name).to_string();
4494 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4495 let actual_ut = self.infer_expr_type_unified(arg, info);
4496 let actual_ty = actual_ut.as_ref().map(|ut| ut.to_rust_string());
4497 let expected_ty = expected_ut.to_rust_string();
4498 if matches!(&arg.kind, ExprKind::StringLit(_))
4502 && expected_ut.is_pointer()
4503 {
4504 syn_expr = crate::syn_codegen::method_call(syn_expr, "as_ptr", vec![]);
4505 }
4506 syn_expr = self.cast_arg_syn_if_needed(syn_expr, actual_ty.as_deref(), &expected_ty);
4507 }
4508 }
4509 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
4510 }
4511
4512 fn cast_arg_syn_if_needed(&self, arg_expr: syn::Expr,
4516 actual_ty: Option<&str>, expected_ty: &str) -> syn::Expr {
4517 use crate::syn_codegen::cast_syn_expr;
4518 if let Some(actual) = actual_ty {
4519 let actual_ut = UnifiedType::from_rust_str(actual);
4521 if self.is_rust_enum_type(&actual_ut) {
4522 if let Some(target) = normalize_integer_type(expected_ty) {
4523 return cast_syn_expr(arg_expr, target);
4524 }
4525 }
4526 let na = normalize_integer_type(actual);
4527 let ne = normalize_integer_type(expected_ty);
4528 if let (Some(a), Some(e)) = (na, ne) {
4529 if !integer_types_compatible(a, e) {
4530 return cast_syn_expr(arg_expr, e);
4531 }
4532 return arg_expr;
4533 }
4534 if actual != expected_ty {
4536 let actual_ut = UnifiedType::from_rust_str(actual);
4537 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4538 if actual_ut.is_pointer() && expected_ut.is_pointer()
4539 && is_sv_subtype_cast(&actual_ut, &expected_ut) {
4540 let cast_ty = if actual.contains("*const") {
4541 expected_ty.replace("*mut", "*const")
4542 } else {
4543 expected_ty.to_string()
4544 };
4545 return cast_syn_expr(arg_expr, &cast_ty);
4546 }
4547 if actual_ut.is_pointer() && expected_ut.is_pointer()
4553 && expected_ut.is_void_pointer()
4554 {
4555 return cast_syn_expr(arg_expr, expected_ty);
4556 }
4557 if pointer_inner_compatible(&actual_ut, &expected_ut) {
4563 let top_mut_to_const = !actual_ut.is_const_pointer()
4564 && expected_ut.is_const_pointer();
4565 let top_const_same = actual_ut.is_const_pointer()
4566 == expected_ut.is_const_pointer();
4567 let inner_exact_match = actual_ut.inner_type()
4569 .zip(expected_ut.inner_type())
4570 .is_some_and(|(a, b)| a.to_rust_string() == b.to_rust_string());
4571 let auto_coerces = (top_mut_to_const || top_const_same)
4572 && inner_exact_match;
4573 if !auto_coerces {
4574 return cast_syn_expr(arg_expr, expected_ty);
4575 }
4576 }
4577 }
4578 return arg_expr;
4579 }
4580 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4582 if expected_ut.is_pointer() {
4583 if let Some(inner) = expected_ut.inner_type() {
4584 if let UnifiedType::Named(name) = inner {
4585 let n = name.as_str();
4586 if matches!(n, "SV" | "GV" | "HV" | "AV" | "CV" | "IO") {
4587 if matches!(&arg_expr, syn::Expr::Call(_) | syn::Expr::MethodCall(_)) {
4588 return cast_syn_expr(arg_expr, expected_ty);
4589 }
4590 }
4591 }
4592 }
4593 }
4594 arg_expr
4595 }
4596
4597 fn try_build_common_macro_fn_call(
4613 &mut self,
4614 func: &Expr,
4615 args: &[Expr],
4616 info: Option<&MacroInferInfo>,
4617 ) -> Option<syn::Expr> {
4618 use crate::syn_codegen::*;
4619
4620 let member_id = match &func.kind {
4621 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => *member,
4622 _ => return None,
4623 };
4624
4625 let mut is_fn_ptr = self
4627 .fields_dict
4628 .and_then(|d| d.canonical_field(member_id).map(|(_, f)| f.is_fn_pointer))
4629 .unwrap_or(false);
4630
4631 if !is_fn_ptr {
4636 let field_name = self.interner.get(member_id);
4637 if let Some(ut) = self.field_type_map.get(field_name) {
4638 let ty_str = ut.to_rust_string();
4639 if type_str_is_fn_pointer(&ty_str) {
4640 is_fn_ptr = true;
4641 } else if let Some(dict) = self.rust_decl_dict {
4642 if let Some(alias) = dict.types.get(&ty_str) {
4643 if type_str_is_fn_pointer(&alias.ty) {
4644 is_fn_ptr = true;
4645 }
4646 }
4647 }
4648 }
4649 }
4650
4651 if !is_fn_ptr {
4652 return None;
4653 }
4654
4655 let field_access = self.build_syn_expr(func, info);
4657 let callee = method_call(field_access, "unwrap_unchecked", vec![]);
4659
4660 let mut punctuated = syn::punctuated::Punctuated::new();
4662 for (i, arg) in args.iter().enumerate() {
4663 let s = self.build_arg_string_unified(arg, info, None, i);
4664 let parsed = syn::parse_str(&s).unwrap_or_else(|_| int_lit(0));
4665 punctuated.push(parsed);
4666 }
4667
4668 Some(syn::Expr::Call(syn::ExprCall {
4669 attrs: vec![],
4670 func: Box::new(callee),
4671 paren_token: Default::default(),
4672 args: punctuated,
4673 }))
4674 }
4675
4676 fn build_lvalue_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
4678 if let ExprKind::MacroCall { expanded, .. } = &expr.kind {
4679 return self.build_syn_expr(expanded, info);
4680 }
4681 if let ExprKind::Call { func, args } = &expr.kind {
4682 if let Some(expanded) = self.try_expand_call_as_lvalue_syn(func, args, info) {
4683 return expanded;
4684 }
4685 let syn_expr = self.build_syn_expr(expr, info);
4686 let s = crate::syn_codegen::expr_to_string(&syn_expr);
4687 self.codegen_errors.push(format!("invalid lvalue: {} cannot be assigned to", s));
4688 return syn_expr;
4689 }
4690 self.build_syn_expr(expr, info)
4691 }
4692
4693 fn build_inc_dec_syn_expr(&mut self, inner: &Expr, info: Option<&MacroInferInfo>,
4696 is_inc: bool, is_post: bool) -> syn::Expr {
4697 use crate::syn_codegen::*;
4698 let lv = self.build_lvalue_syn_expr(inner, info);
4699 let is_ptr = self.is_pointer_expr_unified(inner, info)
4700 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer());
4701 let step_stmt: syn::Stmt = if is_ptr {
4703 let method = if is_inc { "wrapping_add" } else { "wrapping_sub" };
4705 let call = method_call(lv.clone(), method, vec![int_lit(1)]);
4706 semi_stmt(assign_expr(lv.clone(), call))
4707 } else {
4708 let op = if is_inc {
4709 syn::BinOp::AddAssign(Default::default())
4710 } else {
4711 syn::BinOp::SubAssign(Default::default())
4712 };
4713 semi_stmt(assign_op_expr(lv.clone(), op, int_lit(1)))
4714 };
4715 if is_post {
4716 let save = let_stmt("_t", lv.clone());
4718 block_with_value(vec![save, step_stmt], ident_expr("_t"))
4719 } else {
4720 block_with_value(vec![step_stmt], lv)
4722 }
4723 }
4724
4725 fn build_assign_syn_expr(&mut self, op: AssignOp, lhs: &Expr, rhs: &Expr,
4728 info: Option<&MacroInferInfo>) -> syn::Expr {
4729 use crate::syn_codegen::*;
4730 let l = self.build_lvalue_syn_expr(lhs, info);
4731 let lhs_ut = self.infer_expr_type_unified(lhs, info);
4732
4733 let r: syn::Expr = if is_null_literal(rhs) && op == AssignOp::Assign {
4735 match &lhs_ut {
4736 Some(lut) if lut.is_pointer() => {
4737 if lut.is_const_pointer() {
4738 syn::parse_str("std::ptr::null()").unwrap_or_else(|_| int_lit(0))
4739 } else {
4740 syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0))
4741 }
4742 }
4743 Some(_) => int_lit(0),
4744 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
4745 }
4746 } else {
4747 let mut r_expr = self.build_syn_expr(rhs, info);
4748 if op == AssignOp::Assign {
4750 if let Some(ref lut) = lhs_ut {
4752 if lut.is_float() {
4753 if let ExprKind::IntLit(n) = &rhs.kind {
4754 r_expr = syn::parse_str(&format!("{}.0", n))
4755 .unwrap_or_else(|_| int_lit(0));
4756 }
4757 }
4758 }
4759 if let Some(ref lut) = lhs_ut {
4760 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4761 let ls = lut.to_rust_string();
4762 let rs = rut.to_rust_string();
4763 if let (Some(nl), Some(nr)) = (
4764 normalize_integer_type(&ls),
4765 normalize_integer_type(&rs),
4766 ) {
4767 if !integer_types_compatible(nl, nr) {
4768 r_expr = cast_syn_expr(r_expr, nl);
4769 }
4770 }
4771 else if lut.is_pointer() && rut.is_pointer()
4773 && lut.is_const_pointer() != rut.is_const_pointer()
4774 {
4775 r_expr = cast_syn_expr(r_expr, &ls);
4776 }
4777 else if lut.is_pointer() && rut.is_pointer()
4779 && ls != rs
4780 && is_sv_subtype_cast(&rut, lut)
4781 {
4782 r_expr = cast_syn_expr(r_expr, &ls);
4783 }
4784 }
4785 }
4786 }
4787 r_expr
4788 };
4789
4790 if op == AssignOp::Assign {
4794 if let syn::Expr::MethodCall(mc) = &l {
4795 if mc.args.is_empty() {
4796 let method_name = mc.method.to_string();
4797 if self.is_bitfield_method(&method_name) {
4798 let setter_name = format!("set_{}", method_name);
4799 let arg_val = if let Some(dict) = self.rust_decl_dict {
4803 let ret_ty = dict.bitfield_method_types.iter()
4806 .find(|((_, m), _)| m == &method_name)
4807 .map(|(_, ty)| ty.clone());
4808 if let Some(ty) = ret_ty {
4809 cast_syn_expr(r, &ty)
4810 } else {
4811 r
4812 }
4813 } else {
4814 r
4815 };
4816 let setter_call = method_call(
4817 (*mc.receiver).clone(),
4818 &setter_name,
4819 vec![arg_val],
4820 );
4821 let stmt = semi_stmt(setter_call);
4822 return block_with_value(vec![stmt], l);
4823 }
4824 }
4825 }
4826 }
4827
4828 let stmt: syn::Stmt = match op {
4830 AssignOp::Assign => semi_stmt(assign_expr(l.clone(), r)),
4831 AssignOp::AddAssign | AssignOp::SubAssign => {
4832 let is_ptr = self.is_pointer_expr_unified(lhs, info)
4833 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer());
4834 if is_ptr {
4835 let method = if op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
4837 let r_usize = cast_syn_expr(r, "usize");
4838 let call = method_call(l.clone(), method, vec![r_usize]);
4839 semi_stmt(assign_expr(l.clone(), call))
4840 } else {
4841 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4842 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
4843 }
4844 }
4845 AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign => {
4846 let lt = &lhs_ut;
4850 let rt = self.infer_expr_type_unified(rhs, info);
4851 let r_final = {
4852 let mut casted = false;
4853 let mut ret = r;
4854 if let (Some(lut), Some(rut)) = (lt, &rt) {
4855 let ls = lut.to_rust_string();
4856 let rs = rut.to_rust_string();
4857 let nl = normalize_integer_type(&ls);
4858 let nr = normalize_integer_type(&rs);
4859 if nl.is_some() && nr.is_some() && nl != nr {
4860 ret = cast_syn_expr(ret, nl.unwrap());
4861 casted = true;
4862 }
4863 if !casted && self.is_rust_enum_type(rut) && nl.is_some() {
4865 ret = cast_syn_expr(ret, nl.unwrap());
4866 casted = true;
4867 }
4868 }
4869 if !casted {
4870 if let (Some(lut), None) = (lt, &rt) {
4871 let ls = lut.to_rust_string();
4872 if let Some(nl) = normalize_integer_type(&ls) {
4873 ret = cast_syn_expr(ret, nl);
4874 }
4875 }
4876 }
4877 ret
4878 };
4879 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4880 semi_stmt(assign_op_expr(l.clone(), syn_op, r_final))
4881 }
4882 _ => {
4883 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4884 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
4885 }
4886 };
4887 block_with_value(vec![stmt], l)
4888 }
4889
4890 fn build_lvalue_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
4892 let syn_expr = self.build_lvalue_syn_expr(expr, info);
4893 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
4894 }
4895
4896 fn build_syn_expr_with_type_hint(&mut self, expr: &Expr, info: Option<&MacroInferInfo>,
4898 type_hint: Option<&str>) -> syn::Expr {
4899 use crate::syn_codegen::*;
4900 if let Some(ty) = type_hint {
4901 let ut = UnifiedType::from_rust_str(ty);
4902 if ut.is_pointer() && is_null_literal(expr) {
4903 return syn::parse_str(&null_ptr_expr(&ut)).unwrap_or_else(|_| int_lit(0));
4904 }
4905 if ut.is_bool() {
4906 match &expr.kind {
4907 ExprKind::IntLit(0) => return syn::parse_str("false").unwrap(),
4908 ExprKind::IntLit(1) => return syn::parse_str("true").unwrap(),
4909 _ => {}
4910 }
4911 }
4912 }
4913 self.build_syn_expr(expr, info)
4914 }
4915
4916 fn build_return_stmt(&mut self, expr: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
4926 use crate::syn_codegen::*;
4927 if let Some(ref rt) = self.current_return_type {
4928 if rt.is_pointer() && is_null_literal(expr) {
4929 return format!("{}return {};", indent, null_ptr_expr(rt));
4930 }
4931 if rt.is_bool() {
4932 match &expr.kind {
4933 ExprKind::IntLit(0) => return format!("{}return false;", indent),
4934 ExprKind::IntLit(1) => return format!("{}return true;", indent),
4935 _ => {
4936 let mut syn_expr = self.build_syn_expr(expr, info);
4937 if !self.is_bool_expr_with_dict(expr) && !is_bool_syn_expr(&syn_expr) {
4938 syn_expr = wrap_as_bool(syn_expr);
4939 }
4940 let s = normalize_parens(&expr_to_string(&syn_expr));
4941 return format!("{}return {};", indent, s);
4942 }
4943 }
4944 }
4945 }
4946 let mut syn_expr = self.build_syn_expr(expr, info);
4947 syn_expr = self.cast_return_syn_expr_if_needed(expr, info, syn_expr);
4948 let s = normalize_parens(&expr_to_string(&syn_expr));
4949 format!("{}return {};", indent, s)
4950 }
4951
4952 fn cast_return_syn_expr_if_needed(&self, expr: &Expr, info: Option<&MacroInferInfo>,
4955 syn_expr: syn::Expr) -> syn::Expr {
4956 let Some(ret_ut) = &self.current_return_type else { return syn_expr };
4957 let Some(expr_ut) = self.infer_expr_type_unified(expr, info) else { return syn_expr };
4958 let ret_s = ret_ut.to_rust_string();
4959 let expr_s = expr_ut.to_rust_string();
4960 if self.is_rust_enum_type(&expr_ut) {
4962 if let Some(nr) = normalize_integer_type(&ret_s) {
4963 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
4964 }
4965 }
4966 if let (Some(nr), Some(ne)) = (normalize_integer_type(&ret_s), normalize_integer_type(&expr_s)) {
4967 if !integer_types_compatible(nr, ne) {
4968 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
4969 }
4970 }
4971 if ret_ut.is_pointer() && expr_ut.is_pointer() && ret_s != expr_s
4975 && pointer_inner_compatible(ret_ut, &expr_ut)
4976 {
4977 return crate::syn_codegen::cast_syn_expr(syn_expr, &ret_s);
4978 }
4979 syn_expr
4980 }
4981
4982 fn build_assign_stmt(&mut self, op: &AssignOp, lhs: &Expr, rhs: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
4988 use crate::syn_codegen::*;
4989 let l = self.build_lvalue_string(lhs, info);
4990 let lhs_ut = self.infer_expr_type_unified(lhs, info);
4991
4992 let r_syn: syn::Expr = if is_null_literal(rhs) && *op == AssignOp::Assign {
4994 match &lhs_ut {
4995 Some(lut) if lut.is_pointer() => {
4996 let s = if lut.is_const_pointer() { "std::ptr::null()" } else { "std::ptr::null_mut()" };
4997 syn::parse_str(s).unwrap_or_else(|_| int_lit(0))
4998 }
4999 Some(_) => int_lit(0),
5000 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
5001 }
5002 } else {
5003 let mut r_syn = self.build_syn_expr(rhs, info);
5004 if *op == AssignOp::Assign {
5006 if let Some(ref lut) = lhs_ut {
5008 if lut.is_float() {
5009 if let ExprKind::IntLit(n) = &rhs.kind {
5010 r_syn = syn::parse_str(&format!("{}.0", n))
5011 .unwrap_or_else(|_| int_lit(0));
5012 }
5013 }
5014 }
5015 if let Some(ref lut) = lhs_ut {
5016 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
5017 let ls = lut.to_rust_string();
5018 let rs = rut.to_rust_string();
5019 if self.is_rust_enum_type(&rut) {
5021 if let Some(nl) = normalize_integer_type(&ls) {
5022 r_syn = cast_syn_expr(r_syn, nl);
5023 }
5024 } else if let (Some(nl), Some(nr)) = (normalize_integer_type(&ls), normalize_integer_type(&rs)) {
5025 if nl != nr {
5028 r_syn = cast_syn_expr(r_syn, nl);
5029 }
5030 }
5031 if pointer_const_differs(lut, &rut) {
5034 r_syn = cast_syn_expr(r_syn, &ls);
5035 } else if lut.is_pointer() && rut.is_pointer()
5036 && ls != rs
5037 && pointer_inner_compatible(lut, &rut)
5038 {
5039 r_syn = cast_syn_expr(r_syn, &ls);
5040 }
5041 else if lut.is_pointer() && rut.is_pointer()
5044 && ls != rs
5045 && is_sv_subtype_cast(&rut, lut)
5046 {
5047 r_syn = cast_syn_expr(r_syn, &ls);
5048 }
5049 }
5050 }
5051 } else if matches!(op, AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign) {
5052 let rt = self.infer_expr_type_unified(rhs, info);
5053 if let (Some(lut), Some(rut)) = (&lhs_ut, &rt) {
5054 let ls = lut.to_rust_string();
5055 let rs = rut.to_rust_string();
5056 let nl = normalize_integer_type(&ls);
5057 let nr = normalize_integer_type(&rs);
5058 if nl.is_some() && nr.is_some() && nl != nr {
5059 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5060 } else if self.is_rust_enum_type(rut) && nl.is_some() {
5061 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5063 }
5064 } else if let (Some(lut), None) = (&lhs_ut, &rt) {
5065 let ls = lut.to_rust_string();
5066 if let Some(nl) = normalize_integer_type(&ls) {
5067 r_syn = cast_syn_expr(r_syn, nl);
5068 }
5069 }
5070 }
5071 r_syn
5072 };
5073
5074 match op {
5075 AssignOp::Assign => {
5076 let r = normalize_parens(&expr_to_string(&r_syn));
5077 format!("{}{} = {};", indent, l, r)
5078 }
5079 AssignOp::AddAssign | AssignOp::SubAssign => {
5080 if self.is_pointer_expr_unified(lhs, info)
5081 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer()) {
5082 let method = if *op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
5083 let r_usize = cast_syn_expr(r_syn, "usize");
5084 let r = expr_to_string(&r_usize);
5085 format!("{}{} = {}.{}({});", indent, l, l, method, r)
5086 } else {
5087 let r = normalize_parens(&expr_to_string(&r_syn));
5088 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5089 }
5090 }
5091 _ => {
5092 let r = normalize_parens(&expr_to_string(&r_syn));
5093 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5094 }
5095 }
5096 }
5097
5098 fn build_expr_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
5100 let syn_expr = self.build_syn_expr(expr, info);
5101 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
5102 }
5103
5104 fn stmt_to_rust(&mut self, stmt: &Stmt, info: &MacroInferInfo) -> String {
5106 match stmt {
5107 Stmt::Expr(Some(expr), _) => {
5108 format!("{};", self.build_expr_string(expr, Some(info)))
5109 }
5110 Stmt::Expr(None, _) => ";".to_string(),
5111 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, "", Some(info)),
5112 Stmt::Return(None, _) => "return;".to_string(),
5113 _ => self.todo_marker("stmt")
5114 }
5115 }
5116
5117 fn type_name_to_rust(&mut self, type_name: &crate::ast::TypeName) -> String {
5119 let base_type = self.decl_specs_to_rust(&type_name.specs);
5121
5122 let mut result = if let Some(ref decl) = type_name.declarator {
5124 self.apply_derived_to_type(&base_type, &decl.derived)
5125 } else {
5126 base_type
5127 };
5128
5129 if type_name.specs.qualifiers.is_const {
5132 if let Some(pos) = result.rfind("*mut ") {
5133 result.replace_range(pos..pos + 5, "*const ");
5134 }
5135 }
5136
5137 result
5138 }
5139
5140 fn decl_specs_to_rust(&mut self, specs: &DeclSpecs) -> String {
5142 for spec in &specs.type_specs {
5144 if let TypeSpec::TypedefName(name) = spec {
5145 if let Some(generic_name) = self.current_type_param_map.get(name) {
5147 return generic_name.clone();
5148 }
5149 let name_str = self.interner.get(*name).to_string();
5150 if !self.known_symbols.contains(&name_str) {
5152 self.codegen_errors.push(format!("undefined type: {}", name_str));
5153 }
5154 return name_str;
5155 }
5156 }
5157
5158 let mut is_void = false;
5160 let mut is_char = false;
5161 let mut is_int = false;
5162 let mut is_short = false;
5163 let mut is_long = 0usize;
5164 let mut is_unsigned = false;
5165 let mut is_float = false;
5166 let mut is_double = false;
5167
5168 for spec in &specs.type_specs {
5169 match spec {
5170 TypeSpec::Void => is_void = true,
5171 TypeSpec::Char => is_char = true,
5172 TypeSpec::Int => is_int = true,
5173 TypeSpec::Short => is_short = true,
5174 TypeSpec::Long => is_long += 1,
5175 TypeSpec::Unsigned => is_unsigned = true,
5176 TypeSpec::Signed => {}
5177 TypeSpec::Float => is_float = true,
5178 TypeSpec::Double => is_double = true,
5179 TypeSpec::Bool => return "bool".to_string(),
5180 TypeSpec::Struct(spec) => {
5181 if let Some(n) = spec.name {
5182 return self.interner.get(n).to_string();
5183 } else {
5184 return self.type_marker().to_string();
5185 }
5186 }
5187 TypeSpec::Union(spec) => {
5188 if let Some(n) = spec.name {
5189 return self.interner.get(n).to_string();
5190 } else {
5191 return self.type_marker().to_string();
5192 }
5193 }
5194 TypeSpec::Enum(spec) => {
5195 if let Some(n) = spec.name {
5196 return self.interner.get(n).to_string();
5197 } else {
5198 return "c_int".to_string();
5199 }
5200 }
5201 _ => {}
5202 }
5203 }
5204
5205 if is_void {
5206 return "()".to_string();
5207 }
5208
5209 if is_float {
5210 return "c_float".to_string();
5211 }
5212
5213 if is_double {
5214 return if is_long > 0 { "c_longdouble".to_string() } else { "c_double".to_string() };
5215 }
5216
5217 if is_char {
5218 return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() };
5219 }
5220
5221 if is_short {
5222 return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() };
5223 }
5224
5225 if is_long >= 2 {
5226 return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() };
5227 }
5228
5229 if is_long == 1 {
5230 return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() };
5231 }
5232
5233 if is_int || is_unsigned {
5234 return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() };
5235 }
5236
5237 self.type_marker().to_string()
5238 }
5239
5240 fn apply_derived_to_type(&mut self, base: &str, derived: &[DerivedDecl]) -> String {
5242 let fn_idx = derived
5244 .iter()
5245 .position(|d| matches!(d, DerivedDecl::Function(_)));
5246
5247 if let Some(idx) = fn_idx {
5248 if let DerivedDecl::Function(param_list) = &derived[idx] {
5249 let is_fn_pointer =
5251 idx > 0 && matches!(derived[idx - 1], DerivedDecl::Pointer(_));
5252
5253 let return_end = if is_fn_pointer { idx - 1 } else { idx };
5255 let return_derived = &derived[..return_end];
5256 let return_type = self.apply_simple_derived(base, return_derived);
5257
5258 let params: Vec<_> = param_list
5260 .params
5261 .iter()
5262 .map(|p| self.param_type_only(p))
5263 .collect();
5264 let params_str = params.join(", ");
5265
5266 let fn_type =
5268 format!("unsafe extern \"C\" fn({}) -> {}", params_str, return_type);
5269
5270 if is_fn_pointer {
5272 return format!("Option<{}>", fn_type);
5273 }
5274 return fn_type;
5275 }
5276 }
5277
5278 self.apply_simple_derived(base, derived)
5280 }
5281
5282 fn apply_simple_derived(&self, base: &str, derived: &[DerivedDecl]) -> String {
5284 self.apply_simple_derived_with_specs_const(base, derived, false)
5285 }
5286
5287 fn apply_simple_derived_with_specs_const(&self, base: &str, derived: &[DerivedDecl], specs_is_const: bool) -> String {
5289 let mut result = base.to_string();
5290 let mut is_first_pointer = true;
5291 for d in derived.iter().rev() {
5292 match d {
5293 DerivedDecl::Pointer(quals) => {
5294 if result == "()" {
5296 result = "c_void".to_string();
5297 }
5298 let pointee_const = if is_first_pointer {
5302 specs_is_const
5303 } else {
5304 quals.is_const
5305 };
5306 if pointee_const {
5307 result = format!("*const {}", result);
5308 } else {
5309 result = format!("*mut {}", result);
5310 }
5311 is_first_pointer = false;
5312 }
5313 DerivedDecl::Array(arr) => {
5314 if result == "()" {
5316 result = "c_void".to_string();
5317 }
5318 if let Some(ref size_expr) = arr.size {
5319 if let ExprKind::IntLit(n) = &size_expr.kind {
5321 result = format!("[{}; {}]", result, n);
5322 } else {
5323 result = format!("*mut {}", result);
5324 }
5325 } else {
5326 result = format!("*mut {}", result);
5327 }
5328 }
5329 DerivedDecl::Function(_) => {
5330 }
5332 }
5333 }
5334 result
5335 }
5336
5337 fn param_type_only(&mut self, param: &ParamDecl) -> String {
5339 let ty = self.decl_specs_to_rust(¶m.specs);
5340 if let Some(ref declarator) = param.declarator {
5341 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5345 } else {
5346 ty
5347 }
5348 }
5349
5350 pub fn generate_inline_fn(mut self, name: crate::InternedStr, func_def: &FunctionDef) -> GeneratedCode {
5352 let name_str = self.interner.get(name);
5353
5354 let mut_params = {
5356 let mut all_names = HashSet::new();
5357 for d in &func_def.declarator.derived {
5359 if let DerivedDecl::Function(param_list) = d {
5360 for p in ¶m_list.params {
5361 if let Some(ref declarator) = p.declarator {
5362 if let Some(param_name) = declarator.name {
5363 all_names.insert(param_name);
5364 }
5365 }
5366 }
5367 }
5368 }
5369 for item in &func_def.body.items {
5371 if let BlockItem::Decl(decl) = item {
5372 for init_decl in &decl.declarators {
5373 if let Some(var_name) = init_decl.declarator.name {
5374 all_names.insert(var_name);
5375 }
5376 }
5377 }
5378 }
5379 let mut result = HashSet::new();
5380 for item in &func_def.body.items {
5381 if let BlockItem::Stmt(stmt) = item {
5382 collect_mut_params_from_stmt(stmt, &all_names, &mut result);
5383 }
5384 }
5385 result
5386 };
5387
5388 self.mut_local_names = mut_params.clone();
5390
5391 let params_str = self.build_fn_param_list(&func_def.declarator.derived, &mut_params);
5393
5394 let return_type = self.decl_specs_to_rust(&func_def.specs);
5396
5397 let return_derived: Vec<_> = func_def.declarator.derived.iter()
5401 .filter(|d| !matches!(d, DerivedDecl::Function(_)))
5402 .cloned()
5403 .collect();
5404 let return_type = self.apply_simple_derived_with_specs_const(&return_type, &return_derived, func_def.specs.qualifiers.is_const);
5405 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
5406
5407 for d in &func_def.declarator.derived {
5409 if let DerivedDecl::Function(param_list) = d {
5410 for p in ¶m_list.params {
5411 if let Some(ref declarator) = p.declarator {
5412 if let Some(param_name) = declarator.name {
5413 let ty = self.param_type_only(p);
5414 self.current_param_types.insert(param_name, UnifiedType::from_rust_str(&ty));
5415 self.current_local_names.insert(param_name);
5416 }
5417 }
5418 }
5419 }
5420 }
5421
5422 self.collect_local_names_recursive(&func_def.body);
5425
5426 let is_thx_dependent = self.perl_threaded
5428 && self.is_inline_fn_thx_dependent(&func_def.declarator.derived);
5429 let thx_info = if is_thx_dependent { " [THX]" } else { "" };
5430
5431 self.dump_ast_comment_for_body(name_str, &func_def.body);
5433
5434 self.writeln(&format!("/// {}{} - inline function", name_str, thx_info));
5436 self.writeln("#[inline]");
5437 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
5438
5439 self.writeln(&format!("pub unsafe fn {}({}) -> {} {{", name_str, params_str, return_type));
5441
5442 let needs_unsafe = func_def.function_call_count > 0 || func_def.deref_count > 0;
5444
5445 if needs_unsafe {
5446 self.writeln(" unsafe {");
5447 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5448 self.buffer.push_str(&body_str);
5449 self.writeln(" }");
5450 } else {
5451 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5452 self.buffer.push_str(&body_str);
5453 }
5454
5455 self.writeln("}");
5456 self.writeln("");
5457
5458 self.into_generated_code()
5459 }
5460
5461 fn build_fn_param_list(&mut self, derived: &[DerivedDecl], mut_params: &HashSet<InternedStr>) -> String {
5463 for d in derived {
5464 if let DerivedDecl::Function(param_list) = d {
5465 if is_void_only_param_list(¶m_list.params) {
5469 return String::new();
5470 }
5471 let params: Vec<_> = param_list.params.iter()
5472 .map(|p| self.param_decl_to_rust(p, mut_params))
5473 .collect();
5474 let mut result = params.join(", ");
5475 if param_list.is_variadic {
5476 if !result.is_empty() {
5477 result.push_str(", ");
5478 }
5479 result.push_str("...");
5480 }
5481 return result;
5482 }
5483 }
5484 String::new()
5485 }
5486
5487 fn is_inline_fn_thx_dependent(&self, derived: &[DerivedDecl]) -> bool {
5491 for d in derived {
5492 if let DerivedDecl::Function(param_list) = d {
5493 if let Some(first_param) = param_list.params.first() {
5494 if let Some(ref declarator) = first_param.declarator {
5495 if let Some(name) = declarator.name {
5496 let name_str = self.interner.get(name);
5497 return name_str == "my_perl";
5498 }
5499 }
5500 }
5501 return false;
5502 }
5503 }
5504 false
5505 }
5506
5507 fn param_decl_to_rust(&mut self, param: &ParamDecl, mut_params: &HashSet<InternedStr>) -> String {
5509 let param_name_interned = param.declarator
5510 .as_ref()
5511 .and_then(|d| d.name);
5512 let name = param_name_interned
5513 .map(|n| escape_rust_keyword(self.interner.get(n)))
5514 .unwrap_or_else(|| "_".to_string());
5515
5516 let ty = self.decl_specs_to_rust(¶m.specs);
5517
5518 let ty = if let Some(ref declarator) = param.declarator {
5520 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5521 } else {
5522 ty
5523 };
5524
5525 if let Some(n) = param_name_interned {
5527 self.current_param_types.insert(n, UnifiedType::from_rust_str(&ty));
5528 }
5529
5530 let mut_prefix = if param_name_interned.is_some_and(|n| mut_params.contains(&n)) {
5531 "mut "
5532 } else {
5533 ""
5534 };
5535
5536 format!("{}{}: {}", mut_prefix, name, ty)
5537 }
5538
5539 fn decl_to_rust_let(&mut self, decl: &Declaration, indent: &str) -> String {
5541 let mut result = String::new();
5542
5543 let base_type = self.decl_specs_to_rust(&decl.specs);
5545
5546 for init_decl in &decl.declarators {
5548 let name = init_decl.declarator.name
5549 .map(|n| escape_rust_keyword(self.interner.get(n)))
5550 .unwrap_or_else(|| "_".to_string());
5551
5552 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
5554
5555 if let Some(ref init) = init_decl.init {
5557 match init {
5558 Initializer::Expr(expr) => {
5559 let mut init_syn = self.build_syn_expr(expr, None);
5564 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5565 let decl_s = ty.clone();
5566 let expr_s = expr_ut.to_rust_string();
5567 let nd = normalize_integer_type(&decl_s);
5568 let ne = normalize_integer_type(&expr_s);
5569 if let (Some(d), Some(e)) = (nd, ne) {
5570 if !integer_types_compatible(d, e) {
5571 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, d);
5572 }
5573 }
5574 }
5575 let decl_is_mut_ptr = ty.contains("*mut ") && !ty.contains("*const ");
5580 let decl_is_const_ptr = ty.contains("*const ") && !ty.contains("*mut ");
5581 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5582 if expr_ut.is_pointer() {
5583 if decl_is_mut_ptr && expr_ut.is_const_pointer() {
5584 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5585 } else if decl_is_const_ptr && !expr_ut.is_const_pointer() {
5586 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5587 }
5588 }
5589 }
5590 let init_expr = normalize_parens(&crate::syn_codegen::expr_to_string(&init_syn));
5591 let init_expr = if is_null_literal(expr) && ty.contains("*mut") {
5593 "std::ptr::null_mut()".to_string()
5594 } else if is_null_literal(expr) && ty.contains("*const") {
5595 "std::ptr::null()".to_string()
5596 } else {
5597 init_expr
5598 };
5599 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5600 result.push_str(&format!("{}let {}{}: {} = {};\n", indent, mut_kw, name, ty, strip_outer_parens(&init_expr)));
5601 }
5602 Initializer::List(_) => {
5603 result.push_str(&format!("{}let {}: {} = /* init list */;\n", indent, name, ty));
5605 }
5606 }
5607 } else {
5608 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5610 result.push_str(&format!("{}let {}{}: {}; // uninitialized\n", indent, mut_kw, name, ty));
5611 }
5612 }
5613
5614 result
5615 }
5616
5617 fn compound_stmt_to_string(&mut self, stmt: &CompoundStmt, indent: &str) -> String {
5619 let mut result = String::new();
5620 for item in &stmt.items {
5621 match item {
5622 BlockItem::Decl(decl) => {
5623 self.collect_decl_types(decl);
5624 result.push_str(&self.decl_to_rust_let(decl, indent));
5625 }
5626 BlockItem::Stmt(s) => {
5627 let rust_stmt = self.stmt_to_rust_inline(s, indent);
5628 result.push_str(&rust_stmt);
5629 result.push('\n');
5630 }
5631 }
5632 }
5633 result
5634 }
5635
5636 fn stmt_to_rust_inline(&mut self, stmt: &Stmt, indent: &str) -> String {
5638 match stmt {
5639 Stmt::Expr(Some(expr), _) => {
5640 if let ExprKind::Assign { op, lhs, rhs } = &expr.kind {
5642 self.build_assign_stmt(op, lhs, rhs, indent, None)
5643 } else {
5644 format!("{}{};", indent, self.build_expr_string(expr, None))
5645 }
5646 }
5647 Stmt::Expr(None, _) => String::new(),
5648 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, indent, None),
5649 Stmt::Return(None, _) => format!("{}return;", indent),
5650 Stmt::If { cond, then_stmt, else_stmt, .. } => {
5651 let cond_str = self.build_expr_string(cond, None);
5652 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5654 let mut result = format!("{}if {} {{\n", indent, normalize_parens(&cond_bool));
5655 let nested_indent = format!("{} ", indent);
5656 result.push_str(&self.stmt_to_rust_inline(then_stmt, &nested_indent));
5657 result.push_str("\n");
5658 result.push_str(&format!("{}}}", indent));
5659 if let Some(else_stmt) = else_stmt {
5660 result.push_str(" else {\n");
5661 result.push_str(&self.stmt_to_rust_inline(else_stmt, &nested_indent));
5662 result.push_str("\n");
5663 result.push_str(&format!("{}}}", indent));
5664 }
5665 result
5666 }
5667 Stmt::Compound(compound) => {
5668 let mut result = format!("{}{{\n", indent);
5669 for item in &compound.items {
5670 match item {
5671 BlockItem::Stmt(s) => {
5672 let nested_indent = format!("{} ", indent);
5673 result.push_str(&self.stmt_to_rust_inline(s, &nested_indent));
5674 result.push_str("\n");
5675 }
5676 BlockItem::Decl(decl) => {
5677 self.collect_decl_types(decl);
5678 let nested_indent = format!("{} ", indent);
5679 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5680 }
5681 }
5682 }
5683 result.push_str(&format!("{}}}", indent));
5684 result
5685 }
5686 Stmt::While { cond, body, .. } => {
5687 let cond_str = self.build_expr_string(cond, None);
5688 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5690 let mut result = format!("{}while {} {{\n", indent, cond_bool);
5691 let nested_indent = format!("{} ", indent);
5692 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5693 result.push_str("\n");
5694 result.push_str(&format!("{}}}", indent));
5695 result
5696 }
5697 Stmt::For { init, cond, step, body, .. } => {
5698 let mut result = format!("{}{{\n", indent);
5699 let nested_indent = format!("{} ", indent);
5700
5701 if let Some(for_init) = init {
5703 match for_init {
5704 ForInit::Expr(expr) => {
5705 result.push_str(&format!("{}{};\n", nested_indent, self.build_expr_string(expr, None)));
5706 }
5707 ForInit::Decl(decl) => {
5708 self.collect_decl_types(decl);
5709 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5710 }
5711 }
5712 }
5713
5714 if let Some(cond_expr) = cond {
5716 let cond_str = self.build_expr_string(cond_expr, None);
5717 let cond_bool = self.wrap_as_bool_condition_inline(cond_expr, &cond_str);
5719 result.push_str(&format!("{}while {} {{\n", nested_indent, cond_bool));
5720 } else {
5721 result.push_str(&format!("{}loop {{\n", nested_indent));
5722 }
5723
5724 let body_indent = format!("{} ", nested_indent);
5725
5726 result.push_str(&self.stmt_to_rust_inline(body, &body_indent));
5728 result.push_str("\n");
5729
5730 if let Some(step_expr) = step {
5732 result.push_str(&format!("{}{};\n", body_indent, self.build_expr_string(step_expr, None)));
5733 }
5734
5735 result.push_str(&format!("{}}}\n", nested_indent));
5736 result.push_str(&format!("{}}}", indent));
5737 result
5738 }
5739 Stmt::DoWhile { body, cond, .. } => {
5740 if is_zero_constant(cond) {
5743 if !stmt_contains_top_level_break(body) {
5748 let mut result = format!("{}{{\n", indent);
5749 let nested_indent = format!("{} ", indent);
5750 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5751 result.push_str("\n");
5752 result.push_str(&format!("{}}}", indent));
5753 return result;
5754 }
5755 let mut result = format!("{}loop {{\n", indent);
5756 let nested_indent = format!("{} ", indent);
5757 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5758 result.push_str("\n");
5759 result.push_str(&format!("{} break;\n", indent));
5760 result.push_str(&format!("{}}}", indent));
5761 return result;
5762 }
5763
5764 let mut result = format!("{}loop {{\n", indent);
5766 let nested_indent = format!("{} ", indent);
5767 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5768 result.push_str("\n");
5769 let cond_str = self.build_expr_string(cond, None);
5770 let break_cond = if is_boolean_expr(cond) {
5774 normalize_parens(&format!("!({})", cond_str))
5775 } else {
5776 format!("{} == 0", cond_str)
5777 };
5778 result.push_str(&format!("{} if {} {{ break; }}\n", indent, break_cond));
5779 result.push_str(&format!("{}}}", indent));
5780 result
5781 }
5782 Stmt::Switch { expr, body, .. } => {
5783 let expr_str = self.build_expr_string(expr, None);
5784 let mut result = format!("{}match {} {{\n", indent, expr_str);
5785 let nested_indent = format!("{} ", indent);
5786
5787 self.collect_switch_cases(body, &nested_indent, &mut result);
5789
5790 result.push_str(&format!("{}}}", indent));
5791 result
5792 }
5793 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5794 let case_val = self.build_expr_string(case_expr, None);
5796 let mut result = format!("{}{} => {{\n", indent, case_val);
5797 let body_indent = format!("{} ", indent);
5798 result.push_str(&self.stmt_to_rust_inline(case_stmt, &body_indent));
5799 result.push_str("\n");
5800 result.push_str(&format!("{}}}", indent));
5801 result
5802 }
5803 Stmt::Default { stmt: default_stmt, .. } => {
5804 let mut result = format!("{}_ => {{\n", indent);
5805 let body_indent = format!("{} ", indent);
5806 result.push_str(&self.stmt_to_rust_inline(default_stmt, &body_indent));
5807 result.push_str("\n");
5808 result.push_str(&format!("{}}}", indent));
5809 result
5810 }
5811 Stmt::Goto(label, _) => {
5812 let label_str = self.interner.get(*label);
5813 format!("{}break '{}; // goto", indent, label_str)
5814 }
5815 Stmt::Label { name, stmt: label_stmt, .. } => {
5816 let label_str = self.interner.get(*name);
5817 let mut result = format!("{}'{}: {{\n", indent, label_str);
5818 let nested_indent = format!("{} ", indent);
5819 result.push_str(&self.stmt_to_rust_inline(label_stmt, &nested_indent));
5820 result.push_str("\n");
5821 result.push_str(&format!("{}}}", indent));
5822 result
5823 }
5824 Stmt::Break(_) => format!("{}break;", indent),
5825 Stmt::Continue(_) => format!("{}continue;", indent),
5826 _ => self.todo_marker(&format!("{:?}", std::mem::discriminant(stmt)))
5827 }
5828 }
5829
5830 fn collect_switch_cases(&mut self, stmt: &Stmt, indent: &str, result: &mut String) {
5832 struct SwitchCase {
5834 patterns: Vec<String>, body_stmts: Vec<String>,
5836 is_default: bool,
5837 }
5838
5839 let mut cases: Vec<SwitchCase> = Vec::new();
5840 let body_indent = format!("{} ", indent);
5841
5842 fn collect_items<'a>(stmt: &'a Stmt, items: &mut Vec<&'a BlockItem>) {
5844 if let Stmt::Compound(compound) = stmt {
5845 for item in &compound.items {
5846 items.push(item);
5847 }
5848 }
5849 }
5850
5851 fn flatten_case_chain<'a>(stmt: &'a Stmt, patterns: &mut Vec<&'a Expr>) -> (&'a Stmt, bool) {
5853 match stmt {
5854 Stmt::Case { expr, stmt: inner_stmt, .. } => {
5855 patterns.push(expr);
5856 flatten_case_chain(inner_stmt, patterns)
5857 }
5858 Stmt::Default { stmt: inner_stmt, .. } => {
5859 (inner_stmt, true)
5861 }
5862 other => (other, false)
5863 }
5864 }
5865
5866 let mut items: Vec<&BlockItem> = Vec::new();
5867 collect_items(stmt, &mut items);
5868
5869 for item in items {
5870 match item {
5871 BlockItem::Stmt(s) => {
5872 match s {
5873 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5874 let mut patterns: Vec<&Expr> = vec![case_expr];
5876 let (final_stmt, has_default) = flatten_case_chain(case_stmt, &mut patterns);
5877
5878 let pattern_strs: Vec<String> = patterns.iter()
5880 .map(|e| self.expr_to_rust_pattern(e))
5881 .collect();
5882
5883 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
5885 vec![]
5886 } else {
5887 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
5888 };
5889 cases.push(SwitchCase {
5890 patterns: pattern_strs,
5891 body_stmts,
5892 is_default: has_default,
5893 });
5894 }
5895 Stmt::Default { stmt: default_stmt, .. } => {
5896 let mut patterns: Vec<&Expr> = Vec::new();
5898 let (final_stmt, _) = flatten_case_chain(default_stmt, &mut patterns);
5899
5900 let pattern_strs: Vec<String> = patterns.iter()
5902 .map(|e| self.expr_to_rust_pattern(e))
5903 .collect();
5904
5905 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
5907 vec![]
5908 } else {
5909 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
5910 };
5911 cases.push(SwitchCase {
5912 patterns: pattern_strs,
5913 body_stmts,
5914 is_default: true,
5915 });
5916 }
5917 Stmt::Break(_) => {
5918 }
5921 other => {
5922 if let Some(last) = cases.last_mut() {
5924 last.body_stmts.push(self.stmt_to_rust_inline(other, &body_indent));
5925 }
5926 }
5928 }
5929 }
5930 BlockItem::Decl(decl) => {
5931 self.collect_decl_types(decl);
5932 if let Some(last) = cases.last_mut() {
5934 last.body_stmts.push(self.decl_to_rust_let(decl, &body_indent));
5935 }
5936 }
5937 }
5938 }
5939
5940 let has_default = cases.iter().any(|c| c.is_default);
5942 for case in &cases {
5943 let pattern = if case.is_default {
5944 if case.patterns.is_empty() {
5945 "_".to_string()
5946 } else {
5947 format!("{} | _", case.patterns.join(" | "))
5949 }
5950 } else {
5951 case.patterns.join(" | ")
5952 };
5953
5954 result.push_str(&format!("{}{} => {{\n", indent, pattern));
5955 for stmt in &case.body_stmts {
5956 result.push_str(stmt);
5957 result.push_str("\n");
5958 }
5959 result.push_str(&format!("{}}}\n", indent));
5960 }
5961 if !has_default {
5965 result.push_str(&format!("{}_ => {{}}\n", indent));
5966 }
5967 }
5968
5969 fn expr_to_field_path(&self, expr: &Expr) -> Option<String> {
5973 match &expr.kind {
5974 ExprKind::Ident(name) => {
5975 Some(self.interner.get(*name).to_string())
5976 }
5977 ExprKind::Member { expr: base, member } => {
5978 let base_path = self.expr_to_field_path(base)?;
5979 let member_name = self.interner.get(*member);
5980 Some(format!("{}.{}", base_path, member_name))
5981 }
5982 _ => None,
5983 }
5984 }
5985
5986
5987 fn expr_to_rust_pattern(&mut self, expr: &Expr) -> String {
5993 match &expr.kind {
5994 ExprKind::Ident(name) => {
5995 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
5997 let enum_str = self.interner.get(enum_name);
5998 let variant_str = self.interner.get(*name);
5999 format!("crate::{}::{}", enum_str, variant_str)
6000 } else {
6001 escape_rust_keyword(self.interner.get(*name))
6002 }
6003 }
6004 _ => self.build_expr_string(expr, None)
6006 }
6007 }
6008}
6009
6010impl<'a, W: Write> CodegenDriver<'a, W> {
6011 pub fn new(
6013 writer: W,
6014 interner: &'a StringInterner,
6015 enum_dict: &'a EnumDict,
6016 macro_ctx: &'a MacroInferContext,
6017 bindings_info: BindingsInfo,
6018 config: CodegenConfig,
6019 ) -> Self {
6020 Self {
6021 writer,
6022 interner,
6023 enum_dict,
6024 macro_ctx,
6025 bindings_info,
6026 config,
6027 stats: CodegenStats::default(),
6028 used_libc_fns: HashSet::new(),
6029 successfully_generated_inlines: HashSet::new(),
6030 generatable_macros: HashSet::new(),
6031 const_pointer_params: HashMap::new(),
6032 bool_return_macros: HashSet::new(),
6033 perl_threaded: true,
6036 }
6037 }
6038
6039 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
6041 self.perl_threaded = threaded;
6042 self
6043 }
6044
6045 pub fn stats(&self) -> &CodegenStats {
6047 &self.stats
6048 }
6049
6050 pub fn generate(&mut self, result: &InferResult) -> io::Result<()> {
6055 self.perl_threaded = result.perl_build_mode.is_threaded();
6057
6058 let missing_structs = crate::struct_emitter::emit_missing_structs(
6061 &result.fields_dict,
6062 result.rust_decl_dict.as_ref(),
6063 self.interner,
6064 );
6065 let static_arrays = crate::static_array_emitter::emit_static_arrays(
6066 &result.global_const_dict,
6067 &result.fields_dict,
6068 result.rust_decl_dict.as_ref(),
6069 self.interner,
6070 );
6071 for n in &static_arrays.emitted_names {
6075 self.bindings_info.static_arrays.insert(n.clone());
6076 }
6077 for (n, t) in &static_arrays.emitted_types {
6078 self.bindings_info.static_types.insert(n.clone(), t.clone());
6079 }
6080
6081 let mut known_symbols = KnownSymbols::new(result, self.interner);
6083 for n in &missing_structs.emitted_struct_names {
6084 known_symbols.insert(n.clone());
6085 }
6086 for n in &missing_structs.emitted_typedef_names {
6087 known_symbols.insert(n.clone());
6088 }
6089
6090 for (struct_name, methods) in &missing_structs.bitfield_methods {
6094 self.bindings_info
6095 .bitfield_methods
6096 .entry(struct_name.clone())
6097 .or_default()
6098 .extend(methods.iter().cloned());
6099 }
6100 writeln!(self.writer, "// Auto-generated Rust bindings")?;
6105 writeln!(self.writer, "// Generated by libperl-macrogen")?;
6108 writeln!(self.writer)?;
6109
6110 self.generate_use_statements()?;
6112
6113 self.generate_enum_imports(result)?;
6115
6116 if !missing_structs.source.is_empty() {
6118 self.writer.write_all(missing_structs.source.as_bytes())?;
6119 }
6120
6121 if !static_arrays.source.is_empty() {
6123 self.writer.write_all(static_arrays.source.as_bytes())?;
6124 }
6125
6126 self.precompute_macro_generability(result, &known_symbols);
6128
6129 for (&name, info) in &result.infer_ctx.macros {
6131 if info.is_bool_return {
6132 self.bool_return_macros.insert(name);
6133 }
6134 }
6135
6136 if self.config.emit_inline_fns {
6138 self.generate_inline_fns(result, &known_symbols)?;
6139 }
6140
6141 if self.config.emit_macros {
6143 self.generate_macros(result, &known_symbols)?;
6144 }
6145
6146 if !self.used_libc_fns.is_empty() {
6148 let mut fns: Vec<_> = self.used_libc_fns.iter().cloned().collect();
6149 fns.sort();
6150 writeln!(self.writer, "use libc::{{{}}};", fns.join(", "))?;
6151 }
6152
6153 Ok(())
6154 }
6155
6156 fn generate_use_statements(&mut self) -> io::Result<()> {
6158 let statements = if self.config.use_statements.is_empty() {
6159 CodegenConfig::default_use_statements()
6160 } else {
6161 self.config.use_statements.clone()
6162 };
6163
6164 if !statements.is_empty() {
6165 for stmt in &statements {
6166 writeln!(self.writer, "{};", stmt)?;
6167 }
6168 writeln!(self.writer)?;
6169 }
6170
6171 Ok(())
6172 }
6173
6174 fn generate_enum_imports(&mut self, result: &InferResult) -> io::Result<()> {
6178 let enum_names = result.enum_dict.target_enum_names(self.interner);
6179 let bindings_enums = result.rust_decl_dict.as_ref().map(|d| &d.enums);
6180
6181 let filtered_names: Vec<_> = enum_names
6183 .into_iter()
6184 .filter(|name| {
6185 bindings_enums.map_or(true, |enums| enums.contains(*name))
6186 })
6187 .collect();
6188
6189 if !filtered_names.is_empty() {
6190 writeln!(self.writer, "// Enum variant imports")?;
6191 for name in filtered_names {
6192 writeln!(self.writer, "#[allow(unused_imports)]")?;
6193 writeln!(self.writer, "use crate::{}::*;", name)?;
6194 }
6195 writeln!(self.writer)?;
6196 }
6197
6198 Ok(())
6199 }
6200
6201 fn precompute_macro_generability(&mut self, result: &InferResult, known_symbols: &KnownSymbols) {
6207 let macros: Vec<_> = result.infer_ctx.macros.iter()
6209 .filter(|(_, info)| self.should_include_macro(info))
6210 .collect();
6211 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6212
6213 let sorted_names = self.topological_sort_macros(¯os);
6215
6216 for name in sorted_names {
6217 let info = result.infer_ctx.macros.get(&name).unwrap();
6218
6219 if info.apidoc_suppressed {
6225 continue;
6226 }
6227
6228 let has_cascade_failure = info.called_functions.iter().any(|called| {
6233 if included_set.contains(called) {
6234 return result.infer_ctx.macros.get(called)
6235 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6236 .unwrap_or(false)
6237 && !self.generatable_macros.contains(called);
6238 }
6239 false
6240 });
6241 if has_cascade_failure {
6242 continue;
6243 }
6244
6245 let status = self.get_macro_status(info);
6247 if status == GenerateStatus::Success {
6248 let codegen = RustCodegen::new(
6250 self.interner, self.enum_dict, self.macro_ctx,
6251 self.bindings_info.clone(), &known_symbols,
6252 result.rust_decl_dict.as_ref(), Some(&result.inline_fn_dict),
6253 ).with_perl_threaded(self.perl_threaded);
6254 let generated = codegen.generate_macro(info);
6255 if generated.is_complete() && !generated.has_unresolved_names() {
6256 self.generatable_macros.insert(name);
6257 }
6258 }
6259 }
6260 }
6261
6262 pub fn generate_inline_fns(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6269 writeln!(self.writer, "// =============================================================================")?;
6270 writeln!(self.writer, "// Inline Functions")?;
6271 writeln!(self.writer, "// =============================================================================")?;
6272 writeln!(self.writer)?;
6273
6274 let mut fns: Vec<_> = result.inline_fn_dict.iter()
6276 .filter(|(_, func_def)| func_def.is_target)
6277 .collect();
6278 fns.sort_by_key(|(name, _)| self.interner.get(**name));
6279
6280 let inline_set: HashSet<InternedStr> = fns.iter().map(|(n, _)| **n).collect();
6282
6283 enum InlineGenResult {
6285 CallsUnavailable,
6286 ContainsGoto,
6287 UnresolvedNames { code: String, unresolved: Vec<String> },
6288 CodegenError { code: String, errors: Vec<String> },
6289 Incomplete { code: String },
6290 Success { code: String, used_libc: HashSet<String> },
6291 Suppressed { reason: String },
6292 }
6293
6294 let mut gen_results: Vec<(InternedStr, InlineGenResult)> = Vec::new();
6295
6296 for (name, func_def) in &fns {
6297 if result.inline_fn_dict.is_apidoc_suppressed(**name) {
6300 let n_str = self.interner.get(**name);
6301 let reason = result.apidoc_patches.skip_reason(n_str)
6302 .unwrap_or("apidoc skip_codegen")
6303 .to_string();
6304 gen_results.push((**name,
6305 InlineGenResult::Suppressed { reason }));
6306 continue;
6307 }
6308
6309 if result.inline_fn_dict.is_calls_unavailable(**name) {
6311 gen_results.push((**name, InlineGenResult::CallsUnavailable));
6312 continue;
6313 }
6314
6315 if block_items_contain_goto(&func_def.body.items) {
6316 gen_results.push((**name, InlineGenResult::ContainsGoto));
6317 continue;
6318 }
6319
6320 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))
6321 .with_perl_threaded(self.perl_threaded)
6322 .with_dump_ast_for(self.config.dump_ast_for.clone())
6323 .with_dump_types_for(self.config.dump_types_for.clone())
6324 .with_fields_dict(&result.fields_dict)
6325 .with_bool_return(false, self.bool_return_macros.clone());
6326 let generated = codegen.generate_inline_fn(**name, func_def);
6327
6328 if generated.has_unresolved_names() {
6329 gen_results.push((**name, InlineGenResult::UnresolvedNames {
6330 code: generated.code,
6331 unresolved: generated.unresolved_names,
6332 }));
6333 } else if !generated.codegen_errors.is_empty() {
6334 gen_results.push((**name, InlineGenResult::CodegenError {
6335 code: generated.code,
6336 errors: generated.codegen_errors,
6337 }));
6338 } else if generated.is_complete() {
6339 gen_results.push((**name, InlineGenResult::Success {
6340 code: generated.code,
6341 used_libc: generated.used_libc_fns,
6342 }));
6343 } else {
6344 gen_results.push((**name, InlineGenResult::Incomplete {
6345 code: generated.code,
6346 }));
6347 }
6348 }
6349
6350 for (name, gen_result) in &gen_results {
6352 if matches!(gen_result, InlineGenResult::Success { .. }) {
6353 self.successfully_generated_inlines.insert(*name);
6354 }
6355 }
6356
6357 let mut changed = true;
6362 while changed {
6363 changed = false;
6364 let current_success = self.successfully_generated_inlines.clone();
6365 for (name, _) in &gen_results {
6366 if !current_success.contains(name) {
6367 continue;
6368 }
6369 if let Some(calls) = result.inline_fn_dict.get_called_functions(*name) {
6370 let has_unavailable = calls.iter().any(|called| {
6371 if inline_set.contains(called) && !current_success.contains(called) {
6373 return true;
6374 }
6375 if let Some(macro_info) = result.infer_ctx.macros.get(called) {
6377 if macro_info.is_target && self.should_include_macro(macro_info) {
6378 if !self.generatable_macros.contains(called) {
6379 return true;
6380 }
6381 }
6382 }
6383 false
6384 });
6385 if has_unavailable {
6386 self.successfully_generated_inlines.remove(name);
6387 changed = true;
6388 }
6389 }
6390 }
6391 }
6392
6393 for (name, gen_result) in gen_results {
6395 match gen_result {
6396 InlineGenResult::CallsUnavailable => {
6397 let name_str = self.interner.get(name);
6398 let calls = result.inline_fn_dict.get_called_functions(name);
6399 let absent: Vec<String> = calls
6402 .map(|cs| cs.iter()
6403 .filter(|c| {
6404 let fn_name = self.interner.get(**c);
6405 !self.is_function_available(**c, fn_name, result)
6406 })
6407 .map(|c| self.interner.get(*c).to_string())
6408 .collect())
6409 .unwrap_or_default();
6410 let cascade_deps: Vec<String> = calls
6411 .map(|cs| cs.iter()
6412 .filter(|c| {
6413 let is_unavailable_inline = result.inline_fn_dict.get(**c).is_some()
6414 && result.inline_fn_dict.is_unavailable_for_codegen(**c);
6415 let is_unavailable_macro = result.infer_ctx.macros.get(c)
6416 .map(|info| info.is_unavailable_for_codegen())
6417 .unwrap_or(false);
6418 is_unavailable_inline || is_unavailable_macro
6419 })
6420 .map(|c| self.interner.get(*c).to_string())
6421 .collect())
6422 .unwrap_or_default();
6423 if absent.is_empty() {
6424 writeln!(self.writer,
6425 "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6426 name_str, cascade_deps.join(", "))?;
6427 } else {
6428 writeln!(self.writer,
6429 "// [CALLS_UNAVAILABLE] {} - calls unavailable function(s): {}",
6430 name_str, absent.join(", "))?;
6431 }
6432 writeln!(self.writer)?;
6433 self.stats.inline_fns_cascade_unavailable += 1;
6434 }
6435 InlineGenResult::ContainsGoto => {
6436 let name_str = self.interner.get(name);
6437 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6438 writeln!(self.writer)?;
6439 self.stats.inline_fns_contains_goto += 1;
6440 }
6441 InlineGenResult::Suppressed { reason } => {
6442 let name_str = self.interner.get(name);
6443 writeln!(self.writer,
6444 "// [CODEGEN_SUPPRESSED] {} - inline function (apidoc patch)",
6445 name_str)?;
6446 writeln!(self.writer, "// Reason: {}", reason)?;
6447 writeln!(self.writer)?;
6448 }
6449 InlineGenResult::UnresolvedNames { code, unresolved } => {
6450 let name_str = self.interner.get(name);
6451 writeln!(self.writer, "// [UNRESOLVED_NAMES] {} - inline function", name_str)?;
6452 writeln!(self.writer, "// Unresolved: {}", unresolved.join(", "))?;
6453 for line in code.lines() {
6454 writeln!(self.writer, "// {}", line)?;
6455 }
6456 writeln!(self.writer)?;
6457 self.stats.inline_fns_unresolved_names += 1;
6458 }
6459 InlineGenResult::CodegenError { code, errors } => {
6460 let name_str = self.interner.get(name);
6461 writeln!(self.writer, "// [CODEGEN_ERROR] {} - inline function", name_str)?;
6462 for err in &errors {
6463 writeln!(self.writer, "// {}", err)?;
6464 }
6465 for line in code.lines() {
6466 writeln!(self.writer, "// {}", line)?;
6467 }
6468 writeln!(self.writer)?;
6469 }
6470 InlineGenResult::Incomplete { code } => {
6471 let name_str = self.interner.get(name);
6472 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {} - inline function", name_str)?;
6473 for line in code.lines() {
6474 writeln!(self.writer, "// {}", line)?;
6475 }
6476 writeln!(self.writer)?;
6477 self.stats.inline_fns_type_incomplete += 1;
6478 }
6479 InlineGenResult::Success { code, used_libc } => {
6480 if self.successfully_generated_inlines.contains(&name) {
6481 write!(self.writer, "{}", code)?;
6483 self.used_libc_fns.extend(used_libc.iter().cloned());
6484 self.stats.inline_fns_success += 1;
6485 } else {
6486 let name_str = self.interner.get(name);
6488 let unavailable: Vec<String> = result.inline_fn_dict.get_called_functions(name)
6489 .map(|calls| calls.iter()
6490 .filter(|c| inline_set.contains(c) && !self.successfully_generated_inlines.contains(c))
6491 .map(|c| self.interner.get(*c).to_string())
6492 .collect())
6493 .unwrap_or_default();
6494 writeln!(self.writer, "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6495 name_str, unavailable.join(", "))?;
6496 for line in code.lines() {
6497 writeln!(self.writer, "// {}", line)?;
6498 }
6499 writeln!(self.writer)?;
6500 self.stats.inline_fns_cascade_unavailable += 1;
6501 }
6502 }
6503 }
6504 }
6505
6506 writeln!(self.writer)?;
6507 Ok(())
6508 }
6509
6510 pub fn generate_macros(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6512 writeln!(self.writer, "// =============================================================================")?;
6513 writeln!(self.writer, "// Macro Functions")?;
6514 writeln!(self.writer, "// =============================================================================")?;
6515 writeln!(self.writer)?;
6516
6517 let macros: Vec<_> = result.infer_ctx.macros.iter()
6519 .filter(|(_, info)| self.should_include_macro(info))
6520 .collect();
6521 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6522
6523 let sorted_names = self.topological_sort_macros(¯os);
6525
6526 let mut callee_const_params: HashMap<InternedStr, HashSet<usize>> = HashMap::new();
6530 let mut bool_return_macros: HashSet<InternedStr> = HashSet::new();
6531 for (&name, info) in &result.infer_ctx.macros {
6532 if !info.const_pointer_positions.is_empty() {
6533 callee_const_params.insert(name, info.const_pointer_positions.clone());
6534 }
6535 if info.is_bool_return {
6536 bool_return_macros.insert(name);
6537 }
6538 }
6539 self.const_pointer_params = callee_const_params;
6540 self.bool_return_macros = bool_return_macros;
6541
6542 let mut successfully_generated: HashSet<InternedStr> = HashSet::new();
6544
6545 for name in sorted_names {
6546 let info = result.infer_ctx.macros.get(&name).unwrap();
6547
6548 if info.apidoc_suppressed {
6552 let name_str_for_patch = self.interner.get(name);
6553 let reason = result.apidoc_patches.skip_reason(name_str_for_patch)
6554 .unwrap_or("apidoc skip_codegen");
6555 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6556 writeln!(self.writer,
6557 "// [CODEGEN_SUPPRESSED] {}{} - macro function (apidoc patch)",
6558 name_str_for_patch, thx_info)?;
6559 writeln!(self.writer, "// Reason: {}", reason)?;
6560 writeln!(self.writer)?;
6561 continue;
6562 }
6563
6564 let unavailable_deps: Vec<String> = info.called_functions.iter()
6570 .filter(|called| {
6571 if included_set.contains(called) {
6573 return result.infer_ctx.macros.get(called)
6574 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6575 .unwrap_or(false)
6576 && !successfully_generated.contains(called);
6577 }
6578 if result.inline_fn_dict.get(**called)
6580 .map(|f| f.is_target)
6581 .unwrap_or(false)
6582 {
6583 return !self.successfully_generated_inlines.contains(called);
6584 }
6585 false
6586 })
6587 .map(|called| self.interner.get(*called).to_string())
6588 .collect();
6589
6590 if !unavailable_deps.is_empty() {
6591 self.generate_macro_cascade_unavailable(info, &unavailable_deps)?;
6592 self.stats.macros_cascade_unavailable += 1;
6593 continue;
6594 }
6595
6596 let status = self.get_macro_status(info);
6598 match status {
6599 GenerateStatus::Success => {
6600 let const_positions = self.const_pointer_params.get(&name)
6602 .cloned().unwrap_or_default();
6603 let is_bool = self.bool_return_macros.contains(&name);
6604 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))
6605 .with_perl_threaded(self.perl_threaded)
6606 .with_dump_ast_for(self.config.dump_ast_for.clone())
6607 .with_dump_types_for(self.config.dump_types_for.clone())
6608 .with_fields_dict(&result.fields_dict)
6609 .with_const_pointer_positions(const_positions)
6610 .with_bool_return(is_bool, self.bool_return_macros.clone());
6611 let generated = codegen.generate_macro(info);
6612
6613 if generated.has_unresolved_names() {
6614 let name_str = self.interner.get(info.name);
6616 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6617 writeln!(self.writer, "// [UNRESOLVED_NAMES] {}{} - macro function", name_str, thx_info)?;
6618 writeln!(self.writer, "// Unresolved: {}", generated.unresolved_names.join(", "))?;
6619 for line in generated.code.lines() {
6620 writeln!(self.writer, "// {}", line)?;
6621 }
6622 writeln!(self.writer)?;
6623 self.stats.macros_unresolved_names += 1;
6624 } else if !generated.codegen_errors.is_empty() {
6625 let name_str = self.interner.get(info.name);
6627 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6628 writeln!(self.writer, "// [CODEGEN_ERROR] {}{} - macro function", name_str, thx_info)?;
6629 for err in &generated.codegen_errors {
6630 writeln!(self.writer, "// {}", err)?;
6631 }
6632 for line in generated.code.lines() {
6633 writeln!(self.writer, "// {}", line)?;
6634 }
6635 writeln!(self.writer)?;
6636 } else if generated.is_complete() {
6637 write!(self.writer, "{}", generated.code)?;
6639 self.used_libc_fns.extend(generated.used_libc_fns.iter().cloned());
6640 self.stats.macros_success += 1;
6641 successfully_generated.insert(name);
6642 } else {
6643 let name_str = self.interner.get(info.name);
6645 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6646 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {}{} - macro function", name_str, thx_info)?;
6647 for line in generated.code.lines() {
6648 writeln!(self.writer, "// {}", line)?;
6649 }
6650 writeln!(self.writer)?;
6651 self.stats.macros_type_incomplete += 1;
6652 }
6653 }
6654 GenerateStatus::ParseFailed => {
6655 self.generate_macro_parse_failed(info)?;
6656 self.stats.macros_parse_failed += 1;
6657 }
6658 GenerateStatus::TypeIncomplete => {
6659 self.generate_macro_type_incomplete(info, result)?;
6660 self.stats.macros_type_incomplete += 1;
6661 }
6662 GenerateStatus::CallsUnavailable => {
6663 let absent: Vec<&str> = info.called_functions.iter()
6667 .filter(|fn_id| {
6668 let fn_name = self.interner.get(**fn_id);
6669 !self.is_function_available(**fn_id, fn_name, result)
6670 })
6671 .map(|fn_id| self.interner.get(*fn_id))
6672 .collect();
6673 if absent.is_empty() {
6674 let cascade_deps: Vec<String> = info.called_functions.iter()
6676 .filter(|fn_id| {
6677 if let Some(m) = result.infer_ctx.macros.get(*fn_id) {
6678 return m.is_unavailable_for_codegen();
6679 }
6680 if result.inline_fn_dict.get(**fn_id).is_some() {
6681 return result.inline_fn_dict
6682 .is_unavailable_for_codegen(**fn_id);
6683 }
6684 false
6685 })
6686 .map(|fn_id| self.interner.get(*fn_id).to_string())
6687 .collect();
6688 self.generate_macro_cascade_unavailable(info, &cascade_deps)?;
6689 self.stats.macros_cascade_unavailable += 1;
6690 } else {
6691 self.generate_macro_calls_unavailable(info, result)?;
6692 self.stats.macros_calls_unavailable += 1;
6693 }
6694 }
6695 GenerateStatus::ContainsGoto => {
6696 let name_str = self.interner.get(info.name);
6697 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6698 writeln!(self.writer)?;
6699 }
6700 GenerateStatus::GenericUnsupported => {
6701 let name_str = self.interner.get(info.name);
6702 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6703 writeln!(self.writer, "// [GENERIC_UNSUPPORTED] {}{} - Rust cannot cast to generic type T", name_str, thx_info)?;
6704 let const_positions = self.const_pointer_params.get(&name)
6706 .cloned().unwrap_or_default();
6707 let is_bool = self.bool_return_macros.contains(&name);
6708 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))
6709 .with_perl_threaded(self.perl_threaded)
6710 .with_fields_dict(&result.fields_dict)
6711 .with_const_pointer_positions(const_positions)
6712 .with_bool_return(is_bool, self.bool_return_macros.clone());
6713 let generated = codegen.generate_macro(info);
6714 for line in generated.code.lines() {
6715 writeln!(self.writer, "// {}", line)?;
6716 }
6717 writeln!(self.writer)?;
6718 self.stats.macros_generic_unsupported += 1;
6719 }
6720 GenerateStatus::Skip => {
6721 }
6723 }
6724 }
6725
6726 Ok(())
6727 }
6728
6729 fn topological_sort_macros(
6733 &self,
6734 macros: &[(&InternedStr, &MacroInferInfo)],
6735 ) -> Vec<InternedStr> {
6736 use std::collections::VecDeque;
6737
6738 let macro_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6739
6740 let mut in_degree: HashMap<InternedStr, usize> = HashMap::new();
6742 let mut dependents: HashMap<InternedStr, Vec<InternedStr>> = HashMap::new();
6743
6744 for (name, _) in macros {
6745 in_degree.insert(**name, 0);
6746 }
6747
6748 for (name, info) in macros {
6749 for used in &info.uses {
6750 if macro_set.contains(used) {
6751 *in_degree.entry(**name).or_insert(0) += 1;
6753 dependents.entry(*used).or_default().push(**name);
6754 }
6755 }
6756 }
6757
6758 let mut queue: VecDeque<InternedStr> = {
6760 let mut zeros: Vec<_> = in_degree.iter()
6761 .filter(|(_, deg)| **deg == 0)
6762 .map(|(name, _)| *name)
6763 .collect();
6764 zeros.sort_by_key(|n| self.interner.get(*n));
6765 zeros.into_iter().collect()
6766 };
6767
6768 let mut result = Vec::with_capacity(macros.len());
6769
6770 while let Some(name) = queue.pop_front() {
6771 result.push(name);
6772 if let Some(deps) = dependents.get(&name) {
6773 let mut newly_ready: Vec<InternedStr> = Vec::new();
6775 for dep in deps {
6776 if let Some(deg) = in_degree.get_mut(dep) {
6777 *deg -= 1;
6778 if *deg == 0 {
6779 newly_ready.push(*dep);
6780 }
6781 }
6782 }
6783 newly_ready.sort_by_key(|n| self.interner.get(*n));
6785 for n in newly_ready {
6786 queue.push_back(n);
6787 }
6788 }
6789 }
6790
6791 if result.len() < macros.len() {
6793 let result_set: HashSet<_> = result.iter().copied().collect();
6794 let mut remaining: Vec<_> = macro_set.iter()
6795 .filter(|n| !result_set.contains(n))
6796 .copied()
6797 .collect();
6798 remaining.sort_by_key(|n| self.interner.get(*n));
6799 result.extend(remaining);
6800 }
6801
6802 result
6803 }
6804
6805 fn generate_macro_cascade_unavailable(
6807 &mut self,
6808 info: &MacroInferInfo,
6809 unavailable_deps: &[String],
6810 ) -> io::Result<()> {
6811 let name_str = self.interner.get(info.name);
6812 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6813 writeln!(self.writer,
6814 "// [CASCADE_UNAVAILABLE] {}{} - dependency not generated: {}",
6815 name_str, thx_info, unavailable_deps.join(", "))?;
6816 writeln!(self.writer)?;
6817 Ok(())
6818 }
6819
6820 fn should_include_macro(&self, info: &MacroInferInfo) -> bool {
6822 if !info.is_target {
6824 return false;
6825 }
6826
6827 if !info.has_body {
6829 return false;
6830 }
6831
6832 info.is_function
6834 }
6835
6836 fn get_macro_status(&self, info: &MacroInferInfo) -> GenerateStatus {
6838 if info.calls_unavailable {
6840 return GenerateStatus::CallsUnavailable;
6841 }
6842
6843 if !info.generic_type_params.is_empty() {
6846 return GenerateStatus::GenericUnsupported;
6847 }
6848
6849 match &info.parse_result {
6850 ParseResult::Unparseable(_) => GenerateStatus::ParseFailed,
6851 ParseResult::Statement(items) => {
6852 if block_items_contain_goto(items) {
6854 return GenerateStatus::ContainsGoto;
6855 }
6856 if info.is_fully_confirmed() {
6857 GenerateStatus::Success
6858 } else {
6859 GenerateStatus::TypeIncomplete
6860 }
6861 }
6862 ParseResult::Expression(_) => {
6863 if info.is_fully_confirmed() {
6864 GenerateStatus::Success
6865 } else {
6866 GenerateStatus::TypeIncomplete
6867 }
6868 }
6869 }
6870 }
6871
6872 fn generate_macro_parse_failed(&mut self, info: &MacroInferInfo) -> io::Result<()> {
6874 let name_str = self.interner.get(info.name);
6875
6876 let params_str = if info.is_function {
6878 let params: Vec<_> = info.params.iter()
6879 .map(|p| self.interner.get(p.name).to_string())
6880 .collect();
6881 format!("({})", params.join(", "))
6882 } else {
6883 String::new()
6884 };
6885
6886 writeln!(self.writer, "// [PARSE_FAILED] {}{}", name_str, params_str)?;
6887
6888 if let ParseResult::Unparseable(Some(err_msg)) = &info.parse_result {
6890 writeln!(self.writer, "// Error: {}", err_msg)?;
6891 }
6892
6893 writeln!(self.writer, "// (tokens not available in parsed form)")?;
6895 writeln!(self.writer)?;
6896
6897 Ok(())
6898 }
6899
6900 fn generate_macro_calls_unavailable(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
6902 let name_str = self.interner.get(info.name);
6903
6904 let params_str = if info.is_function {
6906 let params: Vec<_> = info.params.iter()
6907 .map(|p| self.interner.get(p.name).to_string())
6908 .collect();
6909 format!("({})", params.join(", "))
6910 } else {
6911 String::new()
6912 };
6913
6914 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6916
6917 writeln!(self.writer, "// [CALLS_UNAVAILABLE] {}{}{} - calls unavailable function(s)", name_str, params_str, thx_info)?;
6918
6919 let unavailable_fns: Vec<_> = info.called_functions.iter()
6921 .filter(|&fn_id| {
6922 let fn_name = self.interner.get(*fn_id);
6923 !self.is_function_available(*fn_id, fn_name, result)
6925 })
6926 .map(|fn_id| self.interner.get(*fn_id))
6927 .collect();
6928
6929 if !unavailable_fns.is_empty() {
6930 writeln!(self.writer, "// Unavailable: {}", unavailable_fns.join(", "))?;
6931 }
6932
6933 writeln!(self.writer)?;
6934
6935 Ok(())
6936 }
6937
6938 fn is_function_available(&self, fn_id: crate::InternedStr, fn_name: &str, result: &InferResult) -> bool {
6940 if result.infer_ctx.macros.contains_key(&fn_id) {
6942 return true;
6943 }
6944
6945 if let Some(rust_decl_dict) = &result.rust_decl_dict {
6947 if rust_decl_dict.fns.contains_key(fn_name) {
6948 return true;
6949 }
6950 }
6951
6952 if result.inline_fn_dict.get(fn_id).is_some() {
6954 return true;
6955 }
6956
6957 let builtin_fns = [
6959 "__builtin_expect",
6960 "__builtin_offsetof",
6961 "offsetof",
6962 "__builtin_types_compatible_p",
6963 "__builtin_constant_p",
6964 "__builtin_choose_expr",
6965 "__builtin_unreachable",
6966 "__builtin_trap",
6967 "__builtin_assume",
6968 "__builtin_bswap16",
6969 "__builtin_bswap32",
6970 "__builtin_bswap64",
6971 "__builtin_popcount",
6972 "__builtin_clz",
6973 "__builtin_ctz",
6974 "pthread_mutex_lock",
6975 "pthread_mutex_unlock",
6976 "pthread_rwlock_rdlock",
6977 "pthread_rwlock_wrlock",
6978 "pthread_rwlock_unlock",
6979 "memchr",
6980 "memcpy",
6981 "memmove",
6982 "memset",
6983 "strlen",
6984 "strcmp",
6985 "strncmp",
6986 "strcpy",
6987 "strncpy",
6988 "ASSERT_IS_LITERAL",
6989 "ASSERT_IS_PTR",
6990 "ASSERT_NOT_PTR",
6991 ];
6992
6993 if builtin_fns.contains(&fn_name) {
6994 return true;
6995 }
6996
6997 false
6998 }
6999
7000 fn generate_macro_type_incomplete(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7002 let name_str = self.interner.get(info.name);
7003
7004 let params_str = if info.is_function {
7006 let params: Vec<_> = info.params.iter()
7007 .map(|p| self.interner.get(p.name).to_string())
7008 .collect();
7009 format!("({})", params.join(", "))
7010 } else {
7011 String::new()
7012 };
7013
7014 writeln!(self.writer, "// [TYPE_INCOMPLETE] {}{}", name_str, params_str)?;
7015
7016 writeln!(self.writer, "// Args status: {:?}, Return status: {:?}",
7018 info.args_infer_status, info.return_infer_status)?;
7019
7020 writeln!(self.writer, "// Typed S-expression:")?;
7022 self.write_typed_sexp_comment(info, result)?;
7023
7024 writeln!(self.writer)?;
7025 Ok(())
7026 }
7027
7028 fn write_typed_sexp_comment(&mut self, info: &MacroInferInfo, _result: &InferResult) -> io::Result<()> {
7030 match &info.parse_result {
7031 ParseResult::Expression(expr) => {
7032 self.write_expr_sexp_comment(expr, info, "// ")?;
7033 }
7034 ParseResult::Statement(block_items) => {
7035 for item in block_items {
7036 if let BlockItem::Stmt(stmt) = item {
7037 self.write_stmt_sexp_comment(stmt, info, "// ")?;
7038 }
7039 }
7040 }
7041 ParseResult::Unparseable(_) => {
7042 writeln!(self.writer, "// (unparseable)")?;
7043 }
7044 }
7045 Ok(())
7046 }
7047
7048 fn write_expr_sexp_comment(&mut self, expr: &Expr, info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7050 let mut buf = Vec::new();
7052 {
7053 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7054 let _ = printer.print_expr(expr);
7055 }
7056
7057 let sexp_str = String::from_utf8_lossy(&buf);
7059 let type_info = self.get_expr_type_info(expr, info);
7060
7061 for line in sexp_str.lines() {
7063 writeln!(self.writer, "{}{}", prefix, line)?;
7064 }
7065 if !type_info.is_empty() {
7066 writeln!(self.writer, "{} :type {}", prefix, type_info)?;
7067 }
7068
7069 Ok(())
7070 }
7071
7072 fn write_stmt_sexp_comment(&mut self, stmt: &Stmt, _info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7074 let mut buf = Vec::new();
7075 {
7076 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7077 let _ = printer.print_stmt(stmt);
7078 }
7079
7080 let sexp_str = String::from_utf8_lossy(&buf);
7081 for line in sexp_str.lines() {
7082 writeln!(self.writer, "{}{}", prefix, line)?;
7083 }
7084
7085 Ok(())
7086 }
7087
7088 fn get_expr_type_info(&self, expr: &Expr, info: &MacroInferInfo) -> String {
7090 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
7092 if let Some(first) = constraints.first() {
7093 return first.ty.to_display_string(self.interner);
7094 }
7095 }
7096 "<unknown>".to_string()
7097 }
7098}