1use std::collections::{BTreeMap, BTreeSet, 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 ExprKind::Conditional { then_expr, else_expr, .. } => {
415 is_boolean_expr(then_expr) && is_boolean_expr(else_expr)
416 }
417 _ => false,
418 }
419}
420
421
422fn is_boolean_expr_recursive(expr: &Expr, interner: &StringInterner) -> bool {
424 if is_boolean_expr(expr) {
425 return true;
426 }
427 match &expr.kind {
428 ExprKind::Call { func, args } => {
429 if let ExprKind::Ident(name) = &func.kind {
430 if interner.get(*name) == "__builtin_expect" && !args.is_empty() {
431 return is_boolean_expr_recursive(&args[0], interner);
432 }
433 }
434 }
435 ExprKind::Cast { type_name, expr: inner } => {
437 if type_name.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool)) {
438 return true;
439 }
440 return is_boolean_expr_recursive(inner, interner);
441 }
442 _ => {}
443 }
444 false
445}
446
447pub fn is_boolean_expr_with_context(
449 expr: &Expr,
450 bool_return_macros: &HashSet<InternedStr>,
451 bool_return_externals: &HashSet<InternedStr>,
452) -> bool {
453 if is_boolean_expr(expr) {
454 return true;
455 }
456 match &expr.kind {
457 ExprKind::Call { func, .. } => {
458 if let ExprKind::Ident(name) = &func.kind {
459 return bool_return_macros.contains(name)
460 || bool_return_externals.contains(name);
461 }
462 }
463 ExprKind::MacroCall { name, .. } => {
464 return bool_return_macros.contains(name)
465 || bool_return_externals.contains(name);
466 }
467 _ => {}
468 }
469 false
470}
471
472fn is_type_repr_pointer(ty: &crate::type_repr::TypeRepr) -> bool {
474 use crate::type_repr::TypeRepr;
475 match ty {
476 TypeRepr::CType { derived, .. } => {
477 derived.iter().any(|d| matches!(d, crate::type_repr::CDerivedType::Pointer { .. }))
478 }
479 TypeRepr::RustType { repr, .. } => {
480 matches!(repr, crate::type_repr::RustTypeRepr::Pointer { .. })
481 }
482 TypeRepr::Inferred(inferred) => {
483 inferred.resolved_type()
484 .map(|r| is_type_repr_pointer(r))
485 .unwrap_or(false)
486 }
487 }
488}
489
490fn best_constraint_for_macro_param(
494 info: &MacroInferInfo,
495 param: &MacroParam,
496) -> Option<crate::type_repr::TypeRepr> {
497 let mut best: Option<(&crate::type_repr::TypeRepr, u8)> = None;
498
499 if let Some(constraints) = info.type_env.get_param_constraints(param.name) {
503 for c in constraints {
504 if c.ty.is_void() { continue; }
505 let tier = c.ty.confidence_tier();
506 if best.is_none() || tier < best.unwrap().1 {
507 best = Some((&c.ty, tier));
508 }
509 }
510 }
511
512 let mut all_expr_ids: Vec<crate::ast::ExprId> = info
513 .type_env
514 .param_to_exprs
515 .get(¶m.name)
516 .map(|ids| ids.iter().cloned().collect())
517 .unwrap_or_default();
518 all_expr_ids.push(param.expr_id());
519
520 for expr_id in &all_expr_ids {
521 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
522 for c in constraints {
523 if c.ty.is_void() { continue; }
524 let tier = c.ty.confidence_tier();
525 if best.is_none() || tier < best.unwrap().1 {
526 best = Some((&c.ty, tier));
527 }
528 }
529 }
530 }
531 best.map(|(t, _)| t.clone())
532}
533
534fn substitute_idents(expr: &mut Expr, subs: &HashMap<InternedStr, &Expr>) {
541 if let ExprKind::Ident(name) = &expr.kind {
542 if let Some(replacement) = subs.get(name) {
543 *expr = (*replacement).clone();
544 return;
545 }
546 }
547 match &mut expr.kind {
548 ExprKind::Ident(_)
549 | ExprKind::IntLit(_)
550 | ExprKind::UIntLit(_)
551 | ExprKind::FloatLit(_)
552 | ExprKind::CharLit(_)
553 | ExprKind::StringLit(_)
554 | ExprKind::SizeofType(_)
555 | ExprKind::Alignof(_) => {}
556 ExprKind::Index { expr: e, index } => {
557 substitute_idents(e, subs);
558 substitute_idents(index, subs);
559 }
560 ExprKind::Call { func, args } => {
561 substitute_idents(func, subs);
562 for arg in args {
563 substitute_idents(arg, subs);
564 }
565 }
566 ExprKind::Member { expr: e, .. }
567 | ExprKind::PtrMember { expr: e, .. }
568 | ExprKind::PostInc(e)
569 | ExprKind::PostDec(e)
570 | ExprKind::PreInc(e)
571 | ExprKind::PreDec(e)
572 | ExprKind::AddrOf(e)
573 | ExprKind::Deref(e)
574 | ExprKind::UnaryPlus(e)
575 | ExprKind::UnaryMinus(e)
576 | ExprKind::BitNot(e)
577 | ExprKind::LogNot(e)
578 | ExprKind::Sizeof(e)
579 | ExprKind::Cast { expr: e, .. } => substitute_idents(e, subs),
580 ExprKind::Binary { lhs, rhs, .. }
581 | ExprKind::Assign { lhs, rhs, .. }
582 | ExprKind::Comma { lhs, rhs } => {
583 substitute_idents(lhs, subs);
584 substitute_idents(rhs, subs);
585 }
586 ExprKind::Conditional { cond, then_expr, else_expr } => {
587 substitute_idents(cond, subs);
588 substitute_idents(then_expr, subs);
589 substitute_idents(else_expr, subs);
590 }
591 ExprKind::Assert { condition, .. } => substitute_idents(condition, subs),
592 ExprKind::MacroCall { args, expanded, .. } => {
593 for arg in args {
594 substitute_idents(arg, subs);
595 }
596 substitute_idents(expanded, subs);
597 }
598 ExprKind::BuiltinCall { args, .. } => {
599 for arg in args {
600 if let crate::ast::BuiltinArg::Expr(e) = arg {
601 substitute_idents(e, subs);
602 }
603 }
604 }
605 ExprKind::CompoundLit { init, .. } => {
606 for item in init {
607 if let crate::ast::Initializer::Expr(e) = &mut item.init {
608 substitute_idents(e, subs);
609 }
610 }
611 }
612 ExprKind::StmtExpr(_) => {}
614 }
615}
616
617fn expr_yields_value_for_stmt_use(expr: &syn::Expr) -> bool {
631 match expr {
632 syn::Expr::Block(b) => {
633 matches!(b.block.stmts.last(), Some(syn::Stmt::Expr(_, None)))
634 }
635 syn::Expr::Binary(b) => matches!(
636 b.op,
637 syn::BinOp::And(_) | syn::BinOp::Or(_)
638 ),
639 syn::Expr::Unary(_) => true,
640 syn::Expr::Paren(p) => expr_yields_value_for_stmt_use(&p.expr),
642 _ => false,
643 }
644}
645
646fn is_unsigned_cast_expr(expr_str: &str) -> bool {
649 if let Some(pos) = expr_str.rfind(" as ") {
650 let after = &expr_str[pos + 4..].trim_end_matches(')');
651 matches!(*after, "usize" | "u8" | "u16" | "u32" | "u64" | "u128" | "c_uint" | "c_ulong" | "c_ulonglong")
652 } else {
653 false
654 }
655}
656
657fn is_unsigned_integer_target(ty: &str) -> bool {
660 matches!(ty,
661 "u8" | "u16" | "u32" | "u64" | "u128" | "usize" |
662 "U8" | "U16" | "U32" | "U64" |
663 "UV" | "STRLEN" | "Size_t" | "size_t" | "PERL_UINTMAX_T" |
664 "c_uchar" | "c_ushort" | "c_uint" | "c_ulong" | "c_ulonglong"
665 )
666}
667
668
669fn strip_outer_parens(s: &str) -> &str {
673 let s = s.trim();
674 if s.len() < 2 || !s.starts_with('(') || !s.ends_with(')') {
675 return s;
676 }
677 let inner = &s[1..s.len() - 1];
679 if inner.trim_start().starts_with('{') {
681 return s;
682 }
683 let mut depth = 0i32;
684 for ch in inner.chars() {
685 match ch {
686 '(' | '{' | '[' => depth += 1,
687 ')' | '}' | ']' => {
688 depth -= 1;
689 if depth < 0 {
690 return s;
692 }
693 }
694 _ => {}
695 }
696 }
697 if depth == 0 {
698 inner
699 } else {
700 s
701 }
702}
703
704fn extract_assert_message(expr: &Expr) -> Option<String> {
707 if let ExprKind::LogNot(inner) = &expr.kind {
708 if let ExprKind::StringLit(bytes) = &inner.kind {
709 return Some(String::from_utf8_lossy(bytes).into_owned());
710 }
711 }
712 None
713}
714
715fn decompose_assert_with_message(condition: &Expr) -> Option<(&Expr, String)> {
717 if let ExprKind::Binary { op: BinOp::LogOr, lhs, rhs } = &condition.kind {
718 if let Some(msg) = extract_assert_message(rhs) {
719 return Some((lhs, msg));
720 }
721 }
722 None
723}
724
725fn is_sv_subtype_cast(from: &UnifiedType, to: &UnifiedType) -> bool {
727 let inner_name = |ut: &UnifiedType| -> Option<String> {
730 match ut.inner_type()? {
731 UnifiedType::Named(name) => Some(name.clone()),
732 UnifiedType::Void => Some("c_void".to_string()),
733 _ => None,
734 }
735 };
736 let from_name = match inner_name(from) {
737 Some(n) => n,
738 None => return false,
739 };
740 let to_name = match inner_name(to) {
741 Some(n) => n,
742 None => return false,
743 };
744 const SV_SUBTYPES: &[&str] = &[
748 "GV", "HV", "AV", "CV", "IO", "p5rx", "REGEXP",
749 "gv", "hv", "av", "cv", "io", "regexp",
750 ];
751 let sv_like = |n: &str| n == "SV" || n == "sv";
752 (SV_SUBTYPES.contains(&from_name.as_str()) && sv_like(&to_name))
754 || (sv_like(&from_name) && SV_SUBTYPES.contains(&to_name.as_str()))
755 || (SV_SUBTYPES.contains(&from_name.as_str())
757 && SV_SUBTYPES.contains(&to_name.as_str()))
758 || to_name == "c_void"
760 || from_name == "c_void"
761}
762
763fn is_null_literal(expr: &Expr) -> bool {
764 match &expr.kind {
765 ExprKind::IntLit(0) => true,
766 ExprKind::Cast { expr: inner, .. } => is_null_literal(inner),
767 _ => false,
768 }
769}
770
771fn null_ptr_expr(return_type: &UnifiedType) -> String {
773 if return_type.is_const_pointer() {
774 "std::ptr::null()".to_string()
775 } else {
776 "std::ptr::null_mut()".to_string()
777 }
778}
779
780fn normalize_integer_type(ty: &str) -> Option<&'static str> {
782 match ty {
783 "u8" | "U8" | "c_uchar" => Some("u8"),
784 "u16" | "U16" | "c_ushort" => Some("u16"),
785 "u32" | "U32" | "c_uint" => Some("u32"),
786 "u64" | "U64" | "UV" | "c_ulong" | "c_ulonglong"
787 | "PERL_UINTMAX_T" => Some("u64"),
788 "i8" | "I8" | "c_schar" | "c_char" => Some("i8"),
789 "i16" | "I16" | "c_short" => Some("i16"),
790 "i32" | "I32" | "c_int" => Some("i32"),
791 "i64" | "I64" | "IV" | "c_long" | "c_longlong" => Some("i64"),
792 "usize" | "STRLEN" => Some("usize"),
793 "isize" | "SSize_t" | "ssize_t" | "PADOFFSET" => Some("isize"),
794 "Stack_off_t" => Some("i32"),
797 _ => None,
798 }
799}
800
801fn integer_types_compatible(a: &str, b: &str) -> bool {
803 if a == b { return true; }
804 matches!((a, b),
805 ("i64", "isize") | ("isize", "i64") |
806 ("u64", "usize") | ("usize", "u64")
807 )
808}
809
810fn integer_type_rank(ty: &str) -> Option<(bool, u8)> {
813 match normalize_integer_type(ty)? {
814 "u8" => Some((false, 1)), "i8" => Some((true, 1)),
815 "u16" => Some((false, 2)), "i16" => Some((true, 2)),
816 "u32" => Some((false, 4)), "i32" => Some((true, 4)),
817 "u64" => Some((false, 8)), "i64" => Some((true, 8)),
818 "usize" => Some((false, 8)), "isize" => Some((true, 8)),
819 _ => None,
820 }
821}
822
823fn wider_integer_type(a: &str, b: &str) -> Option<&'static str> {
826 let na = normalize_integer_type(a)?;
827 let nb = normalize_integer_type(b)?;
828 if na == nb { return None; }
829 let (a_signed, a_rank) = integer_type_rank(a)?;
830 let (_b_signed, b_rank) = integer_type_rank(b)?;
831 if a_rank == b_rank {
832 Some(if a_signed { nb } else { na })
834 } else if a_rank > b_rank {
835 Some(na)
836 } else {
837 Some(nb)
838 }
839}
840
841pub fn pointer_inner_compatible(a: &UnifiedType, b: &UnifiedType) -> bool {
848 let a_inner = match a { UnifiedType::Pointer { inner, .. } => inner.as_ref(), _ => return false };
849 let b_inner = match b { UnifiedType::Pointer { inner, .. } => inner.as_ref(), _ => return false };
850 type_inner_compatible(a_inner, b_inner)
851}
852
853fn type_inner_compatible(a: &UnifiedType, b: &UnifiedType) -> bool {
855 if a.is_pointer() && b.is_pointer() {
857 return pointer_inner_compatible(a, b);
858 }
859 let a_s = a.to_rust_string();
861 let b_s = b.to_rust_string();
862 if let (Some(na), Some(nb)) = (normalize_integer_type(&a_s), normalize_integer_type(&b_s)) {
863 return na == nb;
864 }
865 if a.is_void() && b.is_void() { return true; }
867 a_s == b_s
869}
870
871pub fn pointer_const_differs(a: &UnifiedType, b: &UnifiedType) -> bool {
873 if !(a.is_pointer() && b.is_pointer()) { return false; }
874 if a.is_const_pointer() == b.is_const_pointer() { return false; }
875 pointer_inner_compatible(a, b)
876}
877
878pub fn collect_must_mut_pointer_params(
883 parse_result: &ParseResult,
884 params: &[MacroParam],
885 callee_const_params: &HashMap<InternedStr, HashSet<usize>>,
886) -> HashSet<InternedStr> {
887 let param_names: HashSet<InternedStr> = params.iter().map(|p| p.name).collect();
888 let mut result = HashSet::new();
889 match parse_result {
890 ParseResult::Expression(expr) => {
891 collect_must_mut_from_expr(expr, ¶m_names, callee_const_params, &mut result);
892 }
893 ParseResult::Statement(items) => {
894 for item in items {
895 if let BlockItem::Stmt(stmt) = item {
896 collect_must_mut_from_stmt(stmt, ¶m_names, callee_const_params, &mut result);
897 }
898 }
899 }
900 ParseResult::Unparseable(_) => {}
901 }
902 result
903}
904
905pub fn collect_must_mut_from_stmt(
906 stmt: &Stmt,
907 params: &HashSet<InternedStr>,
908 callee_const: &HashMap<InternedStr, HashSet<usize>>,
909 result: &mut HashSet<InternedStr>,
910) {
911 match stmt {
912 Stmt::Expr(Some(expr), _) | Stmt::Return(Some(expr), _) => {
913 collect_must_mut_from_expr(expr, params, callee_const, result);
914 }
915 Stmt::Compound(compound) => {
916 for item in &compound.items {
917 match item {
918 BlockItem::Stmt(s) => collect_must_mut_from_stmt(s, params, callee_const, result),
919 BlockItem::Decl(decl) => {
920 for init_decl in &decl.declarators {
921 if let Some(Initializer::Expr(init)) = &init_decl.init {
922 collect_must_mut_from_expr(init, params, callee_const, result);
923 }
924 }
925 }
926 }
927 }
928 }
929 Stmt::If { cond, then_stmt, else_stmt, .. } => {
930 collect_must_mut_from_expr(cond, params, callee_const, result);
931 collect_must_mut_from_stmt(then_stmt, params, callee_const, result);
932 if let Some(e) = else_stmt {
933 collect_must_mut_from_stmt(e, params, callee_const, result);
934 }
935 }
936 Stmt::While { cond, body, .. } | Stmt::DoWhile { cond, body, .. } => {
937 collect_must_mut_from_expr(cond, params, callee_const, result);
938 collect_must_mut_from_stmt(body, params, callee_const, result);
939 }
940 Stmt::For { init, cond, step, body, .. } => {
941 if let Some(ForInit::Expr(e)) = init { collect_must_mut_from_expr(e, params, callee_const, result); }
942 if let Some(e) = cond { collect_must_mut_from_expr(e, params, callee_const, result); }
943 if let Some(e) = step { collect_must_mut_from_expr(e, params, callee_const, result); }
944 collect_must_mut_from_stmt(body, params, callee_const, result);
945 }
946 Stmt::Switch { expr, body, .. } => {
947 collect_must_mut_from_expr(expr, params, callee_const, result);
948 collect_must_mut_from_stmt(body, params, callee_const, result);
949 }
950 _ => {}
951 }
952}
953
954pub fn collect_must_mut_from_expr(
955 expr: &Expr,
956 params: &HashSet<InternedStr>,
957 callee_const: &HashMap<InternedStr, HashSet<usize>>,
958 result: &mut HashSet<InternedStr>,
959) {
960 match &expr.kind {
961 ExprKind::Assign { lhs, rhs, .. } => {
963 mark_lvalue_mut(lhs, params, result);
964 collect_must_mut_from_expr(lhs, params, callee_const, result);
965 collect_must_mut_from_expr(rhs, params, callee_const, result);
966 }
967 ExprKind::PreInc(inner) | ExprKind::PreDec(inner) |
969 ExprKind::PostInc(inner) | ExprKind::PostDec(inner) => {
970 mark_lvalue_mut(inner, params, result);
971 collect_must_mut_from_expr(inner, params, callee_const, result);
972 }
973 ExprKind::Call { func, args } => {
975 if let ExprKind::Ident(func_name) = &func.kind {
977 let const_arg_positions = callee_const.get(func_name);
978 for (i, arg) in args.iter().enumerate() {
979 if let ExprKind::Ident(arg_name) = &arg.kind {
980 if params.contains(arg_name) {
981 let is_const_at_callee = const_arg_positions
983 .map_or(false, |positions| positions.contains(&i));
984 if !is_const_at_callee {
985 result.insert(*arg_name);
987 }
988 }
989 }
990 collect_must_mut_from_expr(arg, params, callee_const, result);
991 }
992 } else {
993 for arg in args {
994 collect_must_mut_from_expr(arg, params, callee_const, result);
995 }
996 }
997 collect_must_mut_from_expr(func, params, callee_const, result);
998 }
999 ExprKind::Binary { lhs, rhs, .. } | ExprKind::Comma { lhs, rhs } => {
1001 collect_must_mut_from_expr(lhs, params, callee_const, result);
1002 collect_must_mut_from_expr(rhs, params, callee_const, result);
1003 }
1004 ExprKind::Conditional { cond, then_expr, else_expr } => {
1005 collect_must_mut_from_expr(cond, params, callee_const, result);
1006 collect_must_mut_from_expr(then_expr, params, callee_const, result);
1007 collect_must_mut_from_expr(else_expr, params, callee_const, result);
1008 }
1009 ExprKind::MacroCall { name, args, expanded, .. } => {
1011 let const_arg_positions = callee_const.get(name);
1012 for (i, arg) in args.iter().enumerate() {
1013 if let ExprKind::Ident(arg_name) = &arg.kind {
1014 if params.contains(arg_name) {
1015 let is_const_at_callee = const_arg_positions
1016 .map_or(false, |positions| positions.contains(&i));
1017 if !is_const_at_callee {
1018 result.insert(*arg_name);
1019 }
1020 }
1021 }
1022 collect_must_mut_from_expr(arg, params, callee_const, result);
1023 }
1024 collect_must_mut_from_expr(expanded, params, callee_const, result);
1025 }
1026 ExprKind::Deref(inner) | ExprKind::UnaryMinus(inner) | ExprKind::BitNot(inner) |
1027 ExprKind::LogNot(inner) | ExprKind::AddrOf(inner) |
1028 ExprKind::Cast { expr: inner, .. } => {
1029 collect_must_mut_from_expr(inner, params, callee_const, result);
1030 }
1031 ExprKind::Member { expr: inner, .. } | ExprKind::PtrMember { expr: inner, .. } => {
1032 collect_must_mut_from_expr(inner, params, callee_const, result);
1033 }
1034 ExprKind::Sizeof(inner) => {
1035 collect_must_mut_from_expr(inner, params, callee_const, result);
1036 }
1037 ExprKind::Assert { condition, .. } => {
1038 collect_must_mut_from_expr(condition, params, callee_const, result);
1039 }
1040 ExprKind::StmtExpr(compound) => {
1041 for item in &compound.items {
1042 match item {
1043 BlockItem::Stmt(s) => collect_must_mut_from_stmt(s, params, callee_const, result),
1044 BlockItem::Decl(decl) => {
1045 for init_decl in &decl.declarators {
1046 if let Some(Initializer::Expr(init)) = &init_decl.init {
1047 collect_must_mut_from_expr(init, params, callee_const, result);
1048 }
1049 }
1050 }
1051 }
1052 }
1053 }
1054 _ => {}
1055 }
1056}
1057
1058pub fn mark_lvalue_mut(expr: &Expr, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1060 match &expr.kind {
1061 ExprKind::Deref(inner) => {
1063 if let ExprKind::Ident(name) = &inner.kind {
1064 if params.contains(name) {
1065 result.insert(*name);
1066 }
1067 }
1068 mark_lvalue_mut(inner, params, result);
1070 }
1071 ExprKind::PtrMember { expr: inner, .. } => {
1073 if let ExprKind::Ident(name) = &inner.kind {
1074 if params.contains(name) {
1075 result.insert(*name);
1076 }
1077 }
1078 mark_lvalue_mut(inner, params, result);
1079 }
1080 ExprKind::Member { expr: inner, .. } => {
1082 mark_lvalue_mut(inner, params, result);
1083 }
1084 ExprKind::Cast { expr: inner, type_name } => {
1086 if let ExprKind::Ident(name) = &inner.kind {
1087 if params.contains(name) {
1088 let has_non_const_ptr = type_name.declarator.as_ref()
1090 .map(|d| d.derived.iter().any(|dd| {
1091 matches!(dd, crate::ast::DerivedDecl::Pointer(q) if !q.is_const)
1092 }))
1093 .unwrap_or(false);
1094 if has_non_const_ptr {
1095 result.insert(*name);
1096 }
1097 }
1098 }
1099 mark_lvalue_mut(inner, params, result);
1100 }
1101 ExprKind::MacroCall { expanded, args, .. } => {
1103 mark_lvalue_mut(expanded, params, result);
1104 for arg in args {
1106 mark_lvalue_mut(arg, params, result);
1107 }
1108 }
1109 ExprKind::Call { args, .. } => {
1112 for arg in args {
1113 if let ExprKind::Ident(name) = &arg.kind {
1114 if params.contains(name) {
1115 result.insert(*name);
1116 }
1117 }
1118 mark_lvalue_mut(arg, params, result);
1119 }
1120 }
1121 _ => {}
1122 }
1123}
1124
1125fn collect_mut_params(parse_result: &ParseResult, params: &[MacroParam]) -> HashSet<InternedStr> {
1126 let param_names: HashSet<InternedStr> = params.iter().map(|p| p.name).collect();
1127 let mut result = HashSet::new();
1128 match parse_result {
1129 ParseResult::Expression(expr) => collect_mut_params_from_expr(expr, ¶m_names, &mut result),
1130 ParseResult::Statement(items) => {
1131 for item in items {
1132 if let BlockItem::Stmt(stmt) = item {
1133 collect_mut_params_from_stmt(stmt, ¶m_names, &mut result);
1134 }
1135 }
1136 }
1137 ParseResult::Unparseable(_) => {}
1138 }
1139 result
1140}
1141
1142fn collect_mut_params_from_expr(expr: &Expr, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1143 match &expr.kind {
1144 ExprKind::AddrOf(inner) => {
1145 if let ExprKind::Ident(name) = &inner.kind {
1147 if params.contains(name) {
1148 result.insert(*name);
1149 }
1150 }
1151 collect_mut_params_from_expr(inner, params, result);
1152 }
1153 ExprKind::Assign { lhs, rhs, .. } => {
1154 if let ExprKind::Ident(name) = &lhs.kind {
1156 if params.contains(name) {
1157 result.insert(*name);
1158 }
1159 }
1160 collect_mut_params_from_expr(lhs, params, result);
1161 collect_mut_params_from_expr(rhs, params, result);
1162 }
1163 ExprKind::PreInc(inner) | ExprKind::PreDec(inner) |
1164 ExprKind::PostInc(inner) | ExprKind::PostDec(inner) => {
1165 if let ExprKind::Ident(name) = &inner.kind {
1166 if params.contains(name) {
1167 result.insert(*name);
1168 }
1169 }
1170 collect_mut_params_from_expr(inner, params, result);
1171 }
1172 ExprKind::Binary { lhs, rhs, .. } => {
1174 collect_mut_params_from_expr(lhs, params, result);
1175 collect_mut_params_from_expr(rhs, params, result);
1176 }
1177 ExprKind::Deref(inner) | ExprKind::UnaryMinus(inner) | ExprKind::BitNot(inner) |
1178 ExprKind::LogNot(inner) | ExprKind::Cast { expr: inner, .. } => {
1179 collect_mut_params_from_expr(inner, params, result);
1180 }
1181 ExprKind::Call { func, args } => {
1182 collect_mut_params_from_expr(func, params, result);
1183 for arg in args {
1184 collect_mut_params_from_expr(arg, params, result);
1185 }
1186 }
1187 ExprKind::MacroCall { expanded, args, .. } => {
1188 collect_mut_params_from_expr(expanded, params, result);
1189 for arg in args {
1190 collect_mut_params_from_expr(arg, params, result);
1191 }
1192 }
1193 ExprKind::Conditional { cond, then_expr, else_expr } => {
1194 collect_mut_params_from_expr(cond, params, result);
1195 collect_mut_params_from_expr(then_expr, params, result);
1196 collect_mut_params_from_expr(else_expr, params, result);
1197 }
1198 ExprKind::Comma { lhs, rhs } => {
1199 collect_mut_params_from_expr(lhs, params, result);
1200 collect_mut_params_from_expr(rhs, params, result);
1201 }
1202 ExprKind::Member { expr: inner, .. } | ExprKind::PtrMember { expr: inner, .. } => {
1203 collect_mut_params_from_expr(inner, params, result);
1204 }
1205 ExprKind::StmtExpr(compound) => {
1206 for item in &compound.items {
1207 if let BlockItem::Stmt(stmt) = item {
1208 collect_mut_params_from_stmt(stmt, params, result);
1209 }
1210 }
1211 }
1212 _ => {}
1213 }
1214}
1215
1216fn collect_mut_params_from_stmt(stmt: &Stmt, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1217 match stmt {
1218 Stmt::Expr(Some(expr), _) => collect_mut_params_from_expr(expr, params, result),
1219 Stmt::Return(Some(expr), _) => collect_mut_params_from_expr(expr, params, result),
1220 Stmt::If { cond, then_stmt, else_stmt, .. } => {
1221 collect_mut_params_from_expr(cond, params, result);
1222 collect_mut_params_from_stmt(then_stmt, params, result);
1223 if let Some(else_s) = else_stmt {
1224 collect_mut_params_from_stmt(else_s, params, result);
1225 }
1226 }
1227 Stmt::Compound(compound) => {
1228 for item in &compound.items {
1229 if let BlockItem::Stmt(s) = item {
1230 collect_mut_params_from_stmt(s, params, result);
1231 }
1232 }
1233 }
1234 Stmt::While { cond, body, .. } | Stmt::DoWhile { body, cond, .. } => {
1235 collect_mut_params_from_expr(cond, params, result);
1236 collect_mut_params_from_stmt(body, params, result);
1237 }
1238 Stmt::For { init, cond, step, body, .. } => {
1239 if let Some(ForInit::Expr(e)) = init {
1240 collect_mut_params_from_expr(e, params, result);
1241 }
1242 if let Some(c) = cond {
1243 collect_mut_params_from_expr(c, params, result);
1244 }
1245 if let Some(s) = step {
1246 collect_mut_params_from_expr(s, params, result);
1247 }
1248 collect_mut_params_from_stmt(body, params, result);
1249 }
1250 _ => {}
1251 }
1252}
1253
1254fn type_str_is_fn_pointer(ty_str: &str) -> bool {
1261 ty_str.contains("fn(") || ty_str.contains("fn (")
1262}
1263
1264fn build_field_type_map(dict: Option<&RustDeclDict>) -> HashMap<String, UnifiedType> {
1265 let mut map: HashMap<String, UnifiedType> = HashMap::new();
1266 let mut conflicts: HashSet<String> = HashSet::new();
1267 if let Some(dict) = dict {
1268 for st in dict.structs.values() {
1269 for field in &st.fields {
1270 if conflicts.contains(&field.name) {
1271 continue;
1272 }
1273 match map.entry(field.name.clone()) {
1274 std::collections::hash_map::Entry::Vacant(e) => {
1275 e.insert(field.uty.clone());
1276 }
1277 std::collections::hash_map::Entry::Occupied(e) => {
1278 if e.get() != &field.uty {
1279 conflicts.insert(field.name.clone());
1280 e.remove();
1281 }
1282 }
1283 }
1284 }
1285 }
1286 for ((_struct, method), ret_ty) in &dict.bitfield_method_types {
1291 if conflicts.contains(method) {
1292 continue;
1293 }
1294 let uty = UnifiedType::from_rust_str(ret_ty);
1295 match map.entry(method.clone()) {
1296 std::collections::hash_map::Entry::Vacant(e) => {
1297 e.insert(uty);
1298 }
1299 std::collections::hash_map::Entry::Occupied(e) => {
1300 if e.get() != &uty {
1301 conflicts.insert(method.clone());
1302 e.remove();
1303 }
1304 }
1305 }
1306 }
1307 }
1308 map
1309}
1310
1311#[derive(Debug, Clone)]
1313pub struct CodegenConfig {
1314 pub emit_inline_fns: bool,
1316 pub emit_macros: bool,
1318 pub include_source_location: bool,
1320 pub use_statements: Vec<String>,
1323 pub dump_ast_for: Option<String>,
1325 pub dump_types_for: Option<String>,
1327}
1328
1329impl Default for CodegenConfig {
1330 fn default() -> Self {
1331 Self {
1332 emit_inline_fns: true,
1333 emit_macros: true,
1334 include_source_location: true,
1335 use_statements: Vec::new(),
1336 dump_ast_for: None,
1337 dump_types_for: None,
1338 }
1339 }
1340}
1341
1342impl CodegenConfig {
1343 pub fn default_use_statements() -> Vec<String> {
1348 vec![
1349 "#[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(),
1352 "#[allow(non_camel_case_types, dead_code)] type size_t = usize".to_string(),
1353 "#[allow(non_camel_case_types, dead_code)] type ssize_t = isize".to_string(),
1354 "#[allow(non_camel_case_types, dead_code)] type SSize_t = isize".to_string(),
1355 ]
1356 }
1357
1358 pub fn with_use_statements(mut self, statements: Vec<String>) -> Self {
1360 self.use_statements = statements;
1361 self
1362 }
1363
1364 pub fn add_use_statement(mut self, statement: impl Into<String>) -> Self {
1366 self.use_statements.push(statement.into());
1367 self
1368 }
1369}
1370
1371#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1373pub enum GenerateStatus {
1374 Success,
1376 ParseFailed,
1378 TypeIncomplete,
1380 CallsUnavailable,
1382 ContainsGoto,
1384 GenericUnsupported,
1386 Skip,
1388}
1389
1390fn stmt_contains_goto(stmt: &Stmt) -> bool {
1392 match stmt {
1393 Stmt::Goto(_, _) => true,
1394 Stmt::Compound(cs) => block_items_contain_goto(&cs.items),
1395 Stmt::If { then_stmt, else_stmt, .. } => {
1396 stmt_contains_goto(then_stmt)
1397 || else_stmt.as_ref().is_some_and(|s| stmt_contains_goto(s))
1398 }
1399 Stmt::Switch { body, .. }
1400 | Stmt::While { body, .. }
1401 | Stmt::For { body, .. } => stmt_contains_goto(body),
1402 Stmt::DoWhile { body, .. } => stmt_contains_goto(body),
1403 Stmt::Label { stmt, .. } => stmt_contains_goto(stmt),
1404 Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => stmt_contains_goto(stmt),
1405 _ => false,
1406 }
1407}
1408
1409fn block_items_contain_goto(items: &[BlockItem]) -> bool {
1411 items.iter().any(|item| match item {
1412 BlockItem::Stmt(stmt) => stmt_contains_goto(stmt),
1413 BlockItem::Decl(_) => false,
1414 })
1415}
1416
1417fn stmt_contains_top_level_break(stmt: &Stmt) -> bool {
1420 match stmt {
1421 Stmt::Break(_) => true,
1422 Stmt::Compound(cs) => cs.items.iter().any(|item| match item {
1423 BlockItem::Stmt(s) => stmt_contains_top_level_break(s),
1424 BlockItem::Decl(_) => false,
1425 }),
1426 Stmt::If { then_stmt, else_stmt, .. } => {
1427 stmt_contains_top_level_break(then_stmt)
1428 || else_stmt.as_ref().is_some_and(|s| stmt_contains_top_level_break(s))
1429 }
1430 Stmt::Label { stmt, .. } => stmt_contains_top_level_break(stmt),
1431 _ => false,
1434 }
1435}
1436
1437#[derive(Debug, Clone, Default)]
1439pub struct CodegenStats {
1440 pub macros_success: usize,
1442 pub macros_parse_failed: usize,
1444 pub macros_type_incomplete: usize,
1446 pub macros_calls_unavailable: usize,
1448 pub macros_cascade_unavailable: usize,
1450 pub macros_generic_unsupported: usize,
1452 pub macros_unresolved_names: usize,
1454 pub inline_fns_success: usize,
1456 pub inline_fns_type_incomplete: usize,
1458 pub inline_fns_unresolved_names: usize,
1460 pub inline_fns_cascade_unavailable: usize,
1462 pub inline_fns_contains_goto: usize,
1464}
1465
1466#[derive(Debug, Clone, Default)]
1472pub struct CodegenReport {
1473 pub emitted: BTreeSet<String>,
1475 pub skipped: BTreeMap<String, String>,
1477}
1478
1479impl CodegenReport {
1480 fn record_emit(&mut self, name: impl Into<String>) {
1481 self.emitted.insert(name.into());
1482 }
1483
1484 fn record_skip(&mut self, name: impl Into<String>, reason: impl Into<String>) {
1485 self.skipped.insert(name.into(), reason.into());
1486 }
1487
1488 pub fn check_required(&self, required: &[String]) -> Result<(), RequireCodegenError> {
1492 let mut violations = Vec::new();
1493 for name in required {
1494 if self.emitted.contains(name) {
1495 continue;
1496 }
1497 let reason = match self.skipped.get(name) {
1498 Some(r) => r.clone(),
1499 None => "not a codegen target (no apidoc declaration or not defined in headers)"
1500 .to_string(),
1501 };
1502 violations.push(RequireViolation {
1503 name: name.clone(),
1504 reason,
1505 });
1506 }
1507 if violations.is_empty() {
1508 Ok(())
1509 } else {
1510 Err(RequireCodegenError { violations })
1511 }
1512 }
1513}
1514
1515#[derive(Debug, Clone)]
1517pub struct RequireCodegenError {
1518 pub violations: Vec<RequireViolation>,
1519}
1520
1521#[derive(Debug, Clone)]
1523pub struct RequireViolation {
1524 pub name: String,
1525 pub reason: String,
1526}
1527
1528impl std::fmt::Display for RequireCodegenError {
1529 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1530 writeln!(
1531 f,
1532 "require-codegen-list violation: {} function(s) not generated:",
1533 self.violations.len()
1534 )?;
1535 for v in &self.violations {
1536 writeln!(f, " {} - {}", v.name, v.reason)?;
1537 }
1538 Ok(())
1539 }
1540}
1541
1542impl std::error::Error for RequireCodegenError {}
1543
1544#[derive(Debug, Clone)]
1546pub struct GeneratedCode {
1547 pub code: String,
1549 pub incomplete_count: usize,
1551 pub unresolved_names: Vec<String>,
1553 pub used_libc_fns: HashSet<String>,
1555 pub codegen_errors: Vec<String>,
1557}
1558
1559impl GeneratedCode {
1560 pub fn is_complete(&self) -> bool {
1562 self.incomplete_count == 0
1563 }
1564
1565 pub fn has_unresolved_names(&self) -> bool {
1567 !self.unresolved_names.is_empty()
1568 }
1569}
1570
1571pub struct RustCodegen<'a> {
1577 interner: &'a StringInterner,
1578 enum_dict: &'a EnumDict,
1580 macro_ctx: &'a MacroInferContext,
1582 bindings_info: BindingsInfo,
1584 buffer: String,
1586 incomplete_count: usize,
1588 current_type_param_map: HashMap<InternedStr, String>,
1591 current_literal_string_params: HashSet<InternedStr>,
1593 current_return_type: Option<UnifiedType>,
1595 param_substitutions: HashMap<InternedStr, String>,
1598 current_param_types: HashMap<InternedStr, UnifiedType>,
1601 known_symbols: &'a KnownSymbols,
1603 current_local_names: HashSet<InternedStr>,
1605 unresolved_names: Vec<String>,
1607 used_libc_fns: HashSet<String>,
1609 rust_decl_dict: Option<&'a RustDeclDict>,
1611 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1613 fields_dict: Option<&'a crate::fields_dict::FieldsDict>,
1615 field_type_map: HashMap<String, UnifiedType>,
1617 dump_ast_for: Option<String>,
1619 dump_types_for: Option<String>,
1621 const_pointer_positions: HashSet<usize>,
1623 mut_local_names: HashSet<InternedStr>,
1625 codegen_errors: Vec<String>,
1627 is_bool_return: bool,
1629 bool_return_macros: HashSet<InternedStr>,
1631 perl_threaded: bool,
1633}
1634
1635pub struct CodegenDriver<'a, W: Write> {
1640 writer: W,
1641 interner: &'a StringInterner,
1642 enum_dict: &'a EnumDict,
1644 macro_ctx: &'a MacroInferContext,
1646 bindings_info: BindingsInfo,
1648 config: CodegenConfig,
1649 stats: CodegenStats,
1650 report: CodegenReport,
1652 used_libc_fns: HashSet<String>,
1654 successfully_generated_inlines: HashSet<InternedStr>,
1656 generatable_macros: HashSet<InternedStr>,
1658 const_pointer_params: HashMap<InternedStr, HashSet<usize>>,
1660 bool_return_macros: HashSet<InternedStr>,
1662 perl_threaded: bool,
1664}
1665
1666impl<'a> RustCodegen<'a> {
1667 pub fn new(
1669 interner: &'a StringInterner,
1670 enum_dict: &'a EnumDict,
1671 macro_ctx: &'a MacroInferContext,
1672 bindings_info: BindingsInfo,
1673 known_symbols: &'a KnownSymbols,
1674 rust_decl_dict: Option<&'a RustDeclDict>,
1675 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1676 ) -> Self {
1677 Self {
1678 interner,
1679 enum_dict,
1680 macro_ctx,
1681 bindings_info,
1682 buffer: String::new(),
1683 incomplete_count: 0,
1684 current_type_param_map: HashMap::new(),
1685 current_literal_string_params: HashSet::new(),
1686 current_return_type: None,
1687 param_substitutions: HashMap::new(),
1688 current_param_types: HashMap::new(),
1689 known_symbols,
1690 current_local_names: HashSet::new(),
1691 unresolved_names: Vec::new(),
1692 used_libc_fns: HashSet::new(),
1693 rust_decl_dict,
1694 inline_fn_dict,
1695 fields_dict: None,
1696 field_type_map: build_field_type_map(rust_decl_dict),
1697 dump_ast_for: None,
1698 dump_types_for: None,
1699 const_pointer_positions: HashSet::new(),
1700 is_bool_return: false,
1701 bool_return_macros: HashSet::new(),
1702 mut_local_names: HashSet::new(),
1703 codegen_errors: Vec::new(),
1704 perl_threaded: true,
1707 }
1708 }
1709
1710 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
1712 self.perl_threaded = threaded;
1713 self
1714 }
1715
1716 pub fn with_dump_ast_for(mut self, name: Option<String>) -> Self {
1718 self.dump_ast_for = name;
1719 self
1720 }
1721
1722 pub fn with_dump_types_for(mut self, name: Option<String>) -> Self {
1723 self.dump_types_for = name;
1724 self
1725 }
1726
1727 pub fn with_fields_dict(mut self, dict: &'a crate::fields_dict::FieldsDict) -> Self {
1729 self.fields_dict = Some(dict);
1730 for (_name, def) in dict.iter_struct_defs() {
1735 for m in &def.members {
1736 let member_name = self.interner.get(m.name).to_string();
1737 if self.field_type_map.contains_key(&member_name) {
1738 continue;
1739 }
1740 let rust_ty = m.type_repr.to_rust_string(self.interner);
1741 self.field_type_map
1742 .insert(member_name, UnifiedType::from_rust_str(&rust_ty));
1743 }
1744 }
1745 self
1746 }
1747
1748 pub fn with_const_pointer_positions(mut self, positions: HashSet<usize>) -> Self {
1750 self.const_pointer_positions = positions;
1751 self
1752 }
1753
1754 pub fn with_bool_return(mut self, is_bool: bool, bool_macros: HashSet<InternedStr>) -> Self {
1756 self.is_bool_return = is_bool;
1757 self.bool_return_macros = bool_macros;
1758 self
1759 }
1760
1761 fn dump_type_info(&self, name_str: &str, info: &MacroInferInfo, params_str: &str, return_type: &str) {
1764 eprintln!("=== Type dump for {} ===", name_str);
1765 for (i, p) in info.params.iter().enumerate() {
1767 let pname = self.interner.get(p.name);
1768 let is_const = info.const_pointer_positions.contains(&i);
1769 let expr_ids: Vec<_> = info.type_env.param_to_exprs
1771 .get(&p.name)
1772 .map(|ids| ids.iter().cloned().collect())
1773 .unwrap_or_default();
1774 let mut all_ids = expr_ids;
1775 all_ids.push(p.expr_id());
1776 eprintln!(" param[{}] {} (const_position={})", i, pname, is_const);
1777 for eid in &all_ids {
1778 if let Some(constraints) = info.type_env.expr_constraints.get(eid) {
1779 for c in constraints {
1780 eprintln!(" constraint: tier={} rust={} context={} source={:?}",
1781 c.ty.confidence_tier(),
1782 c.ty.to_rust_string(self.interner),
1783 c.context,
1784 match &c.ty {
1785 crate::type_repr::TypeRepr::CType { source, .. } => format!("{:?}", source),
1786 crate::type_repr::TypeRepr::RustType { source, .. } => format!("{:?}", source),
1787 crate::type_repr::TypeRepr::Inferred(i) => format!("Inferred({:?})", std::mem::discriminant(i)),
1788 }
1789 );
1790 }
1791 }
1792 }
1793 }
1794 eprintln!(" params_str: {}", params_str);
1795 eprintln!(" return_type: {}", return_type);
1797 eprintln!(" is_bool_return: {}", info.is_bool_return);
1798 if let Some(ty) = info.get_return_type() {
1799 eprintln!(" return TypeRepr: tier={} rust={}", ty.confidence_tier(), ty.to_rust_string(self.interner));
1800 }
1801 if !info.type_env.return_constraints.is_empty() {
1803 eprintln!(" return_constraints:");
1804 for c in &info.type_env.return_constraints {
1805 eprintln!(" tier={} rust={} context={}", c.ty.confidence_tier(), c.ty.to_rust_string(self.interner), c.context);
1806 }
1807 }
1808 if let ParseResult::Expression(ref expr) = info.parse_result {
1810 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
1811 eprintln!(" root expr constraints:");
1812 for c in constraints {
1813 eprintln!(" tier={} rust={} context={}",
1814 c.ty.confidence_tier(),
1815 c.ty.to_rust_string(self.interner),
1816 c.context,
1817 );
1818 }
1819 }
1820 }
1821 eprintln!("=== End type dump ===");
1822 }
1823
1824 fn dump_ast_comment_for_expr(&mut self, name_str: &str, parse_result: &ParseResult) {
1825 if self.dump_ast_for.as_deref() != Some(name_str) {
1826 return;
1827 }
1828 let sexp = match parse_result {
1829 ParseResult::Expression(expr) => {
1830 let mut buf = Vec::new();
1831 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1832 let _ = printer.print_expr(expr);
1833 String::from_utf8_lossy(&buf).into_owned()
1834 }
1835 ParseResult::Statement(block_items) => {
1836 let mut buf = Vec::new();
1837 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1838 for item in block_items {
1839 if let BlockItem::Stmt(stmt) = item {
1840 let _ = printer.print_stmt(stmt);
1841 } else if let BlockItem::Decl(decl) = item {
1842 let _ = printer.print_declaration(decl);
1843 }
1844 }
1845 String::from_utf8_lossy(&buf).into_owned()
1846 }
1847 ParseResult::Unparseable(msg) => {
1848 format!("(unparseable: {})", msg.as_deref().unwrap_or("unknown"))
1849 }
1850 };
1851 self.writeln(&format!("// [AST dump for {}]", name_str));
1852 for line in sexp.lines() {
1853 self.writeln(&format!("// {}", line));
1854 }
1855 }
1856
1857 fn dump_ast_comment_for_body(&mut self, name_str: &str, body: &CompoundStmt) {
1859 if self.dump_ast_for.as_deref() != Some(name_str) {
1860 return;
1861 }
1862 let mut buf = Vec::new();
1863 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1864 for item in &body.items {
1865 match item {
1866 BlockItem::Stmt(stmt) => { let _ = printer.print_stmt(stmt); }
1867 BlockItem::Decl(decl) => { let _ = printer.print_declaration(decl); }
1868 }
1869 }
1870 let sexp = String::from_utf8_lossy(&buf).into_owned();
1871 self.writeln(&format!("// [AST dump for {}]", name_str));
1872 for line in sexp.lines() {
1873 self.writeln(&format!("// {}", line));
1874 }
1875 }
1876
1877 fn try_expand_call_as_lvalue_syn(&mut self, func: &Expr, args: &[Expr],
1881 info: Option<&MacroInferInfo>) -> Option<syn::Expr> {
1882 if let ExprKind::Ident(name) = &func.kind {
1883 if self.should_emit_as_macro_call(*name) {
1884 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
1885 if let ParseResult::Expression(body) = ¯o_info.parse_result {
1886 let body = body.clone();
1887 let saved_params = std::mem::take(&mut self.param_substitutions);
1888 for (i, param) in macro_info.params.iter().enumerate() {
1889 if let Some(arg) = args.get(i) {
1890 let arg_syn = self.build_syn_expr(arg, info);
1891 let arg_str = crate::syn_codegen::expr_to_string(&arg_syn);
1892 self.param_substitutions.insert(param.name, arg_str);
1893 }
1894 }
1895 let body_syn = self.build_syn_expr(&body, info);
1896 self.param_substitutions = saved_params;
1897 return Some(body_syn);
1898 }
1899 }
1900 }
1901 }
1902 None
1903 }
1904
1905
1906 fn wrap_as_bool_condition_inline(&self, expr: &Expr, expr_str: &str) -> String {
1908 self.wrap_as_bool_condition(expr, expr_str, None)
1909 }
1910
1911 fn infer_expr_type_inline(&self, expr: &Expr) -> Option<UnifiedType> {
1913 self.infer_expr_type_unified(expr, None)
1914 }
1915
1916 fn type_name_to_type_str_readonly(&self, type_name: &crate::ast::TypeName) -> String {
1918 let pointer_count = type_name.declarator.as_ref()
1920 .map(|d| d.derived.iter().filter(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer(_))).count())
1921 .unwrap_or(0);
1922 let is_const_ptr = pointer_count == 1 && type_name.specs.qualifiers.is_const;
1928 let base = self.base_type_str_readonly(&type_name.specs.type_specs);
1930 let mut result = base;
1932 for _ in 0..pointer_count {
1933 let prefix = if is_const_ptr { "*const " } else { "*mut " };
1934 result = format!("{}{}", prefix, result);
1935 }
1936 result
1937 }
1938
1939 fn base_type_str_readonly(&self, type_specs: &[TypeSpec]) -> String {
1941 for spec in type_specs {
1943 if let TypeSpec::TypedefName(name) = spec {
1944 return self.interner.get(*name).to_string();
1945 }
1946 }
1947 for spec in type_specs {
1949 match spec {
1950 TypeSpec::Struct(s) | TypeSpec::Union(s) => {
1951 if let Some(n) = &s.name {
1952 return self.interner.get(*n).to_string();
1953 }
1954 }
1955 TypeSpec::Enum(e) => {
1956 if let Some(n) = &e.name {
1957 return self.interner.get(*n).to_string();
1958 }
1959 }
1960 _ => {}
1961 }
1962 }
1963 let mut is_void = false;
1964 let mut is_char = false;
1965 let mut is_int = false;
1966 let mut is_short = false;
1967 let mut is_long = 0usize;
1968 let mut is_unsigned = false;
1969 for spec in type_specs {
1970 match spec {
1971 TypeSpec::Void => is_void = true,
1972 TypeSpec::Char => is_char = true,
1973 TypeSpec::Int => is_int = true,
1974 TypeSpec::Short => is_short = true,
1975 TypeSpec::Long => is_long += 1,
1976 TypeSpec::Unsigned => is_unsigned = true,
1977 TypeSpec::Signed => {}
1978 TypeSpec::Bool => return "bool".to_string(),
1979 _ => {}
1980 }
1981 }
1982 if is_void { return "c_void".to_string(); }
1983 if is_char { return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() }; }
1984 if is_short { return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() }; }
1985 if is_long >= 2 { return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() }; }
1986 if is_long == 1 { return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() }; }
1987 if is_int || is_unsigned { return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() }; }
1988 "c_int".to_string()
1989 }
1990
1991 fn infer_expr_type(&self, expr: &Expr, info: &MacroInferInfo) -> Option<UnifiedType> {
1993 self.infer_expr_type_unified(expr, Some(info))
1994 }
1995
1996 fn infer_expr_type_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> Option<UnifiedType> {
2005 match &expr.kind {
2006 ExprKind::Ident(name) => {
2007 if let Some(ut) = self.current_param_types.get(name) {
2009 return Some(ut.clone());
2010 }
2011 if let Some(info) = info {
2013 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
2015 let mut best: Option<(UnifiedType, u8)> = None;
2016 for expr_id in expr_ids {
2017 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
2018 for c in constraints {
2019 if c.ty.is_void() { continue; }
2020 let tier = c.ty.confidence_tier();
2021 if best.is_none() || tier < best.as_ref().unwrap().1 {
2022 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
2023 }
2024 }
2025 }
2026 }
2027 if let Some((ut, _)) = best {
2028 return Some(ut);
2029 }
2030 }
2031 if let Some(constraints) = info.type_env.param_constraints.get(name) {
2033 let mut best: Option<(UnifiedType, u8)> = None;
2034 for c in constraints {
2035 if c.ty.is_void() { continue; }
2036 let tier = c.ty.confidence_tier();
2037 if best.is_none() || tier < best.as_ref().unwrap().1 {
2038 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
2039 }
2040 }
2041 if let Some((ut, _)) = best {
2042 return Some(ut);
2043 }
2044 }
2045 }
2046 if let Some(dict) = self.rust_decl_dict {
2048 let name_str = self.interner.get(*name);
2049 if let Some(c) = dict.consts.get(name_str) {
2050 return Some(c.uty.clone());
2051 }
2052 if let Some(ty_str) = dict.static_types.get(name_str) {
2054 return Some(UnifiedType::from_rust_str(ty_str));
2055 }
2056 }
2057 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
2061 let enum_str = self.interner.get(enum_name).to_string();
2062 return Some(UnifiedType::Named(enum_str));
2063 }
2064 None
2065 }
2066 ExprKind::Cast { type_name, .. } => {
2067 Some(UnifiedType::from_rust_str(&self.type_name_to_type_str_readonly(type_name)))
2068 }
2069 ExprKind::Member { expr: base, member } | ExprKind::PtrMember { expr: base, member } => {
2070 let resolve_struct_name = |this: &Self| -> Option<String> {
2075 if let Some(info_ref) = info {
2077 if let Some(constraints) = info_ref.type_env.expr_constraints.get(&base.id) {
2078 if let Some(base_ty) = constraints.first().map(|c| &c.ty) {
2079 let sn = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
2080 base_ty.pointee_name()
2081 } else {
2082 base_ty.type_name()
2083 };
2084 if let Some(n) = sn {
2085 return Some(this.interner.get(n).to_string());
2086 }
2087 }
2088 }
2089 }
2090 let base_ut = this.infer_expr_type_unified(base, info)?;
2093 let target = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
2094 base_ut.inner_type()?
2095 } else {
2096 &base_ut
2097 };
2098 if let UnifiedType::Named(n) = target {
2099 return Some(n.clone());
2100 }
2101 None
2102 };
2103
2104 let member_str = self.interner.get(*member);
2105 let fd_ty: Option<UnifiedType> = self.fields_dict.and_then(|fd| {
2112 let struct_name_str = resolve_struct_name(self)?;
2113 let struct_name = self.interner.lookup(&struct_name_str)?;
2114 let member_ty = fd.member_type(struct_name, *member)?;
2115 let rust_ty = member_ty.to_rust_string(self.interner);
2116 if rust_ty.contains("/* fn */") {
2117 return None;
2118 }
2119 Some(UnifiedType::from_rust_str(&rust_ty))
2120 });
2121 let ftm_ty = self.field_type_map.get(member_str).cloned();
2122 match (&fd_ty, &ftm_ty) {
2125 (Some(fd_ut), Some(ftm_ut))
2126 if fd_ut.is_pointer() && ftm_ut.to_rust_string().starts_with('[') =>
2127 {
2128 return ftm_ty;
2129 }
2130 _ => {}
2131 }
2132 fd_ty.or(ftm_ty)
2133 }
2134 ExprKind::Deref(inner) => {
2135 let inner_ut = self.infer_expr_type_unified(inner, info)?;
2136 inner_ut.inner_type().cloned()
2137 }
2138 ExprKind::Index { expr: base, .. } => {
2139 let base_ut = self.infer_expr_type_unified(base, info)?;
2142 base_ut.inner_type().cloned()
2143 }
2144 ExprKind::Binary { op, lhs, rhs } => {
2145 match op {
2146 BinOp::Shl | BinOp::Shr => self.infer_expr_type_unified(lhs, info),
2147 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => {
2148 let lt = self.infer_expr_type_unified(lhs, info);
2149 let rt = self.infer_expr_type_unified(rhs, info);
2150 match (<, &rt) {
2151 (Some(l), Some(r)) => {
2152 let ls = l.to_rust_string();
2153 let rs = r.to_rust_string();
2154 wider_integer_type(&ls, &rs)
2155 .map(|w| UnifiedType::from_rust_str(w))
2156 .or(lt)
2157 }
2158 (Some(_), None) => lt,
2159 (None, Some(_)) => rt,
2160 _ => None,
2161 }
2162 }
2163 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt
2164 | BinOp::Le | BinOp::Ge | BinOp::LogAnd | BinOp::LogOr => {
2165 Some(UnifiedType::Bool)
2166 }
2167 _ => {
2168 if *op == BinOp::Sub {
2171 let lp = self.is_pointer_expr_unified(lhs, info)
2172 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
2173 let rp = self.is_pointer_expr_unified(rhs, info)
2174 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
2175 if lp && rp {
2176 return Some(UnifiedType::Named("isize".to_string()));
2177 }
2178 }
2179 let lt = self.infer_expr_type_unified(lhs, info);
2180 if lt.is_some() { return lt; }
2181 self.infer_expr_type_unified(rhs, info)
2182 }
2183 }
2184 }
2185 ExprKind::BitNot(inner) | ExprKind::UnaryMinus(inner) => self.infer_expr_type_unified(inner, info),
2186 ExprKind::CharLit(_) => Some(UnifiedType::from_rust_str("i8")),
2187 ExprKind::UIntLit(_) => Some(UnifiedType::Int { signed: false, size: crate::unified_type::IntSize::LongLong }),
2188 ExprKind::Sizeof(_) | ExprKind::SizeofType(_) => Some(UnifiedType::Named("usize".to_string())),
2193 ExprKind::Call { func, .. } => {
2194 if let ExprKind::Member { expr: receiver, member, .. } = &func.kind {
2196 let method_name = self.interner.get(*member);
2197 if matches!(method_name, "offset" | "wrapping_add" | "wrapping_sub" | "wrapping_offset") {
2198 return self.infer_expr_type_unified(receiver, info);
2199 }
2200 }
2201 if let ExprKind::Ident(name) = &func.kind {
2202 let func_name = self.interner.get(*name);
2203 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2204 return Some(ret_ut.clone());
2205 }
2206 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2208 if let Some(ty) = macro_info.get_return_type() {
2209 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2210 }
2211 }
2212 if let Some(dict) = self.inline_fn_dict {
2214 if let Some(func_def) = dict.get(*name) {
2215 let base = self.base_type_str_readonly(&func_def.specs.type_specs);
2217 let mut result = base;
2218 let pointer_count = func_def.declarator.derived.iter()
2219 .take_while(|d| !matches!(d, crate::ast::DerivedDecl::Function(_)))
2220 .filter(|d| matches!(d, crate::ast::DerivedDecl::Pointer(_)))
2221 .count();
2222 let is_const_ptr = pointer_count == 1
2223 && func_def.specs.qualifiers.is_const;
2224 for _ in 0..pointer_count {
2225 let prefix = if is_const_ptr { "*const " } else { "*mut " };
2226 result = format!("{}{}", prefix, result);
2227 }
2228 return Some(UnifiedType::from_rust_str(&result));
2229 }
2230 }
2231 }
2232 None
2233 }
2234 ExprKind::MacroCall { name, expanded, .. } => {
2235 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2236 if let Some(ty) = macro_info.get_return_type() {
2237 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2238 }
2239 }
2240 self.infer_expr_type_unified(expanded, info)
2241 }
2242 ExprKind::Conditional { then_expr, else_expr, .. } => {
2243 if is_null_literal(then_expr) {
2244 return self.infer_expr_type_unified(else_expr, info);
2245 }
2246 if is_null_literal(else_expr) {
2247 return self.infer_expr_type_unified(then_expr, info);
2248 }
2249 let tt = self.infer_expr_type_unified(then_expr, info);
2250 let et = self.infer_expr_type_unified(else_expr, info);
2251 match (&tt, &et) {
2252 (Some(t), Some(e)) if t.is_void_pointer() && e.is_concrete_pointer() => et,
2253 (Some(t), Some(e)) if e.is_void_pointer() && t.is_concrete_pointer() => tt,
2254 (Some(_), _) => tt,
2255 (None, _) => et,
2256 }
2257 }
2258 _ => None,
2259 }
2260 }
2261
2262 fn is_pointer_expr_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2264 match &expr.kind {
2265 ExprKind::Ident(name) => {
2266 if let Some(ut) = self.current_param_types.get(name) {
2267 return ut.is_pointer();
2268 }
2269 if let Some(info) = info {
2270 if let Some(constraints) = info.type_env.param_constraints.get(name) {
2271 for c in constraints {
2272 if is_type_repr_pointer(&c.ty) {
2273 return true;
2274 }
2275 }
2276 }
2277 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
2278 for expr_id in expr_ids {
2279 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
2280 for c in constraints {
2281 if is_type_repr_pointer(&c.ty) {
2282 return true;
2283 }
2284 }
2285 }
2286 }
2287 }
2288 }
2289 false
2290 }
2291 ExprKind::Cast { type_name, .. } => {
2292 type_name.declarator.as_ref()
2293 .map(|d| d.derived.iter().any(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer { .. })))
2294 .unwrap_or(false)
2295 }
2296 ExprKind::AddrOf(_) => true,
2297 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => {
2298 let member_str = self.interner.get(*member);
2299 self.field_type_map.get(member_str).is_some_and(|ut| ut.is_pointer())
2300 }
2301 ExprKind::Deref(inner) => {
2302 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
2303 if let Some(derefed) = ut.inner_type() {
2304 return derefed.is_pointer();
2305 }
2306 }
2307 false
2308 }
2309 ExprKind::Call { func, .. } | ExprKind::MacroCall { expanded: func, .. } => {
2310 let check_func = match &expr.kind {
2311 ExprKind::MacroCall { name, .. } => {
2312 if let Some(callee) = self.macro_ctx.macros.get(name) {
2313 for c in &callee.type_env.return_constraints {
2314 if is_type_repr_pointer(&c.ty) { return true; }
2315 }
2316 }
2317 func
2318 }
2319 _ => func,
2320 };
2321 if let ExprKind::Ident(name) = &check_func.kind {
2322 if let Some(callee) = self.macro_ctx.macros.get(name) {
2323 for c in &callee.type_env.return_constraints {
2324 if is_type_repr_pointer(&c.ty) { return true; }
2325 }
2326 }
2327 if let Some(ret_ut) = self.get_callee_return_type(self.interner.get(*name)) {
2328 return ret_ut.is_pointer();
2329 }
2330 }
2331 false
2332 }
2333 ExprKind::Binary { op, lhs, rhs } => {
2334 match op {
2335 BinOp::Add => self.is_pointer_expr_unified(lhs, info) || self.is_pointer_expr_unified(rhs, info),
2336 BinOp::Sub => self.is_pointer_expr_unified(lhs, info) && !self.is_pointer_expr_unified(rhs, info),
2337 _ => false,
2338 }
2339 }
2340 _ => false,
2341 }
2342 }
2343
2344 fn is_option_fn_pointer_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2351 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2355 let member_str = self.interner.get(*member);
2356 if let Some(ut) = self.field_type_map.get(member_str) {
2357 let ty_str = ut.to_rust_string();
2358 if type_str_is_fn_pointer(&ty_str) {
2359 return true;
2360 }
2361 if let Some(dict) = self.rust_decl_dict {
2362 if let Some(alias) = dict.types.get(&ty_str) {
2363 if type_str_is_fn_pointer(&alias.ty) {
2364 return true;
2365 }
2366 }
2367 }
2368 }
2369 }
2370 let Some(ut) = self.infer_expr_type_unified(expr, info) else { return false };
2371 let ty_str = ut.to_rust_string();
2372 if type_str_is_fn_pointer(&ty_str) {
2373 return true;
2374 }
2375 if let Some(dict) = self.rust_decl_dict {
2377 if let Some(alias) = dict.types.get(&ty_str) {
2378 if type_str_is_fn_pointer(&alias.ty) {
2379 return true;
2380 }
2381 }
2382 }
2383 false
2384 }
2385
2386 fn wrap_as_bool_condition(&self, expr: &Expr, expr_str: &str, info: Option<&MacroInferInfo>) -> String {
2388 if self.is_bool_expr_with_dict(expr) {
2389 return expr_str.to_string();
2390 }
2391 if let ExprKind::Ident(name) = &expr.kind {
2393 if let Some(ut) = self.current_param_types.get(name) {
2394 if ut.is_bool() {
2395 return expr_str.to_string();
2396 }
2397 }
2398 }
2399 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2401 let member_str = self.interner.get(*member);
2402 if let Some(ut) = self.field_type_map.get(member_str) {
2403 if ut.is_bool() {
2404 return expr_str.to_string();
2405 }
2406 }
2407 }
2408 if let ExprKind::Call { func, args, .. } = &expr.kind {
2410 if let ExprKind::Ident(name) = &func.kind {
2411 if self.interner.get(*name) == "__builtin_expect" && !args.is_empty() {
2412 return self.wrap_as_bool_condition(&args[0], expr_str, info);
2413 }
2414 }
2415 }
2416 if expr_str.ends_with(" as bool)") || expr_str.ends_with("!= 0)") || expr_str.ends_with(".is_null()") {
2417 return expr_str.to_string();
2418 }
2419 if self.is_option_fn_pointer_expr(expr, info) {
2422 return format!("{}.is_some()", expr_str);
2423 }
2424 if self.is_pointer_expr_unified(expr, info)
2425 || self.infer_expr_type_unified(expr, info).is_some_and(|ut| ut.is_pointer()) {
2426 return format!("!({}).is_null()", expr_str);
2431 }
2432 format!("({} != 0)", strip_outer_parens(expr_str))
2433 }
2434
2435 fn needs_my_perl_for_call(&self, func_name: crate::InternedStr, actual_arg_count: usize) -> bool {
2442 if !self.perl_threaded {
2446 return false;
2447 }
2448 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2449 if callee_info.is_thx_dependent {
2450 let expected_count = callee_info.params.len() + 1;
2452 return actual_arg_count + 1 == expected_count;
2454 }
2455 }
2456 false
2457 }
2458
2459 fn is_static_array_expr(&self, expr: &Expr) -> bool {
2461 if let ExprKind::Ident(name) = &expr.kind {
2462 let name_str = self.interner.get(*name);
2463 self.bindings_info.static_arrays.contains(name_str)
2464 } else {
2465 false
2466 }
2467 }
2468
2469 fn is_array_like_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2477 if self.is_static_array_expr(expr) {
2478 return true;
2479 }
2480 if let ExprKind::Member { expr: base, member }
2482 | ExprKind::PtrMember { expr: base, member } = &expr.kind
2483 {
2484 if let (Some(fd), Some(info)) = (self.fields_dict, info) {
2485 if let Some(constraints) = info.type_env.expr_constraints.get(&base.id) {
2486 if let Some(base_type) = constraints.first().map(|c| &c.ty) {
2487 let struct_name = match &expr.kind {
2488 ExprKind::PtrMember { .. } => base_type.pointee_name(),
2489 _ => base_type.type_name(),
2490 };
2491 if let Some(sn) = struct_name {
2492 if fd.is_flexible_array_field(sn, *member) {
2493 return false;
2494 }
2495 }
2496 }
2497 }
2498 }
2499 }
2500 if let Some(ut) = self.infer_expr_type_unified(expr, info) {
2501 let s = ut.to_rust_string();
2502 if s.starts_with('[') && s.contains(';') {
2503 return true;
2504 }
2505 }
2506 false
2507 }
2508
2509 fn is_bitfield_method(&self, member_name: &str) -> bool {
2513 self.bindings_info.bitfield_methods.values()
2514 .any(|methods| methods.contains(member_name))
2515 }
2516
2517 fn get_callee_generic_params(&self, func_name: InternedStr) -> Option<&HashMap<i32, String>> {
2519 let callee_info = self.macro_ctx.macros.get(&func_name)?;
2520 if callee_info.generic_type_params.is_empty() {
2521 return None;
2522 }
2523 if callee_info.generic_type_params.keys().any(|&k| k >= 0) {
2524 Some(&callee_info.generic_type_params)
2525 } else {
2526 None
2527 }
2528 }
2529
2530 fn is_enum_cast_target(&self, type_name: &crate::ast::TypeName) -> bool {
2532 for spec in &type_name.specs.type_specs {
2533 match spec {
2534 TypeSpec::TypedefName(name) => return self.enum_dict.is_target_enum(*name),
2535 TypeSpec::Enum(_) => return true,
2536 _ => {}
2537 }
2538 }
2539 false
2540 }
2541
2542 fn callee_expects_literal_string(&self, func_name: InternedStr, arg_index: usize) -> bool {
2544 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2545 return callee_info.literal_string_params.contains(&arg_index);
2546 }
2547 false
2548 }
2549
2550 fn get_callee_param_type(&self, func_name: &str, arg_index: usize) -> Option<&UnifiedType> {
2552 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2553 f.params.get(arg_index).map(|p| &p.uty)
2554 })
2555 }
2556
2557 fn get_callee_param_type_extended(&mut self, func_name: &str, arg_index: usize) -> Option<UnifiedType> {
2559 if let Some(ut) = libc_fn_param_type(func_name, arg_index) {
2563 return Some(ut);
2564 }
2565 if let Some(ut) = self.get_callee_param_type(func_name, arg_index) {
2567 return Some(ut.clone());
2568 }
2569 if let Some(interned) = self.interner.lookup(func_name) {
2570 if let Some(dict) = self.inline_fn_dict {
2572 if let Some(func_def) = dict.get(interned) {
2573 for d in &func_def.declarator.derived {
2574 if let DerivedDecl::Function(param_list) = d {
2575 if let Some(param) = param_list.params.get(arg_index) {
2576 let ty = self.param_type_only(param);
2577 return Some(UnifiedType::from_rust_str(&ty));
2578 }
2579 break;
2580 }
2581 }
2582 }
2583 }
2584 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2586 let macro_param_idx = if self.perl_threaded && macro_info.is_thx_dependent {
2589 if arg_index == 0 {
2590 return Some(UnifiedType::from_rust_str("*mut PerlInterpreter"));
2591 }
2592 arg_index - 1
2593 } else {
2594 arg_index
2595 };
2596 if let Some(param) = macro_info.params.get(macro_param_idx) {
2597 if let Some(mut ty) = best_constraint_for_macro_param(macro_info, param) {
2601 let should_be_const = macro_info
2604 .const_pointer_positions
2605 .contains(¯o_param_idx);
2606 if should_be_const {
2607 ty.make_outer_pointer_const();
2608 } else if ty.has_outer_pointer() {
2609 ty.make_outer_pointer_mut();
2610 }
2611 let rust_ty = ty.to_rust_string(self.interner);
2612 return Some(UnifiedType::from_rust_str(&rust_ty));
2613 }
2614 }
2615 }
2616 }
2617 None
2618 }
2619
2620 fn callee_param_is_bool(&self, func_name: &str, arg_index: usize) -> bool {
2622 if let Some(param_ut) = self.get_callee_param_type(func_name, arg_index) {
2624 return param_ut.is_bool();
2625 }
2626 if let Some(interned) = self.interner.lookup(func_name) {
2628 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2629 let macro_arg_index = if self.perl_threaded
2632 && macro_info.is_thx_dependent
2633 && arg_index > 0
2634 {
2635 arg_index - 1
2636 } else {
2637 arg_index
2638 };
2639 if let Some(param) = macro_info.params.get(macro_arg_index) {
2640 if let Some(expr_ids) = macro_info.type_env.param_to_exprs.get(¶m.name) {
2642 for expr_id in expr_ids {
2643 if let Some(constraints) = macro_info.type_env.expr_constraints.get(expr_id) {
2644 for c in constraints {
2645 let rust_ty = c.ty.to_rust_string(self.interner);
2646 if rust_ty == "bool" {
2647 return true;
2648 }
2649 }
2650 }
2651 }
2652 }
2653 }
2654 }
2655 if let Some(dict) = self.inline_fn_dict {
2657 if let Some(func_def) = dict.get(interned) {
2658 for d in &func_def.declarator.derived {
2659 if let DerivedDecl::Function(param_list) = d {
2660 if let Some(param) = param_list.params.get(arg_index) {
2661 let has_bool = param.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2662 let has_pointer = param.declarator.as_ref().map_or(false, |decl| {
2663 decl.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)))
2664 });
2665 if has_bool && !has_pointer {
2666 return true;
2667 }
2668 }
2669 break;
2670 }
2671 }
2672 }
2673 }
2674 }
2675 false
2676 }
2677
2678 fn get_callee_return_type(&self, func_name: &str) -> Option<&UnifiedType> {
2680 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2681 f.uret_ty.as_ref()
2682 })
2683 }
2684
2685 fn is_rust_enum_type(&self, ut: &UnifiedType) -> bool {
2689 if let UnifiedType::Named(name) = ut {
2690 if let Some(dict) = self.rust_decl_dict {
2691 return dict.enums.contains(name.as_str());
2692 }
2693 }
2694 false
2695 }
2696
2697 fn is_bool_expr_with_dict(&self, expr: &Expr) -> bool {
2699 if is_boolean_expr_recursive(expr, self.interner) {
2700 return true;
2701 }
2702 if let ExprKind::Index { expr: base, .. } = &expr.kind {
2704 if let ExprKind::Ident(name) = &base.kind {
2705 if let Some(dict) = self.rust_decl_dict {
2706 let name_str = self.interner.get(*name);
2707 if let Some(c) = dict.consts.get(name_str) {
2708 if let Some(inner) = c.uty.inner_type() {
2709 if inner.is_bool() {
2710 return true;
2711 }
2712 }
2713 }
2714 if dict.statics.contains(name_str) && name_str.starts_with("PL_valid_types_") {
2716 return true;
2717 }
2718 }
2719 }
2720 }
2721 if let ExprKind::Ident(name) = &expr.kind {
2723 if let Some(ut) = self.current_param_types.get(name) {
2724 if ut.is_bool() {
2725 return true;
2726 }
2727 }
2728 }
2729 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2731 let member_str = self.interner.get(*member);
2732 if let Some(ut) = self.field_type_map.get(member_str) {
2733 if ut.is_bool() {
2734 return true;
2735 }
2736 }
2737 }
2738 if let ExprKind::Call { func, .. } = &expr.kind {
2740 if let ExprKind::Ident(name) = &func.kind {
2741 if self.bool_return_macros.contains(name) {
2743 return true;
2744 }
2745 let func_name = self.interner.get(*name);
2746 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2748 return ret_ut.is_bool();
2749 }
2750 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2752 if let Some(ty) = macro_info.get_return_type() {
2753 let rust_ty = ty.to_rust_string(self.interner);
2754 return rust_ty == "bool";
2755 }
2756 }
2757 if let Some(dict) = self.inline_fn_dict {
2759 if let Some(func_def) = dict.get(*name) {
2760 let has_bool_return = func_def.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2761 let has_return_pointer = func_def.declarator.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)));
2762 if has_bool_return && !has_return_pointer {
2763 return true;
2764 }
2765 }
2766 }
2767 }
2768 }
2769 if let ExprKind::MacroCall { name, .. } = &expr.kind {
2771 if self.bool_return_macros.contains(name) {
2772 return true;
2773 }
2774 }
2775 false
2776 }
2777
2778 fn find_literal_string_ident<'b>(&self, expr: &'b Expr) -> Option<&'b InternedStr> {
2781 match &expr.kind {
2782 ExprKind::Ident(name) if self.current_literal_string_params.contains(name) => {
2783 Some(name)
2784 }
2785 ExprKind::Call { func, args } if args.len() == 1 => {
2786 if let ExprKind::Ident(fname) = &func.kind {
2788 let func_name = self.interner.get(*fname);
2789 if func_name == "ASSERT_IS_LITERAL"
2790 || func_name == "ASSERT_IS_PTR"
2791 || func_name == "ASSERT_NOT_PTR"
2792 {
2793 return self.find_literal_string_ident(&args[0]);
2794 }
2795 }
2796 None
2797 }
2798 _ => None,
2799 }
2800 }
2801
2802
2803 fn should_emit_as_macro_call(&self, name: crate::InternedStr) -> bool {
2810 if let Some(info) = self.macro_ctx.macros.get(&name) {
2812 return info.is_parseable() && !info.calls_unavailable;
2814 }
2815 false
2816 }
2817
2818 fn unknown_marker(&mut self) -> &'static str {
2820 self.incomplete_count += 1;
2821 "/* unknown */"
2822 }
2823
2824 fn todo_marker(&mut self, msg: &str) -> String {
2826 self.incomplete_count += 1;
2827 format!("/* TODO: {} */", msg)
2828 }
2829
2830 fn type_marker(&mut self) -> &'static str {
2832 self.incomplete_count += 1;
2833 "/* type */"
2834 }
2835
2836 fn collect_decl_names(&mut self, decl: &Declaration) {
2839 let base_type = self.decl_specs_to_rust(&decl.specs);
2840 for init_decl in &decl.declarators {
2841 if let Some(name) = init_decl.declarator.name {
2842 self.current_local_names.insert(name);
2843 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2844 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2845 }
2846 }
2847 }
2848
2849 fn collect_local_names_recursive(&mut self, body: &CompoundStmt) {
2855 for item in &body.items {
2856 self.collect_local_names_from_block_item(item);
2857 }
2858 }
2859
2860 fn collect_local_names_from_block_item(&mut self, item: &BlockItem) {
2861 match item {
2862 BlockItem::Decl(d) => self.collect_decl_names(d),
2863 BlockItem::Stmt(s) => self.collect_local_names_from_stmt(s),
2864 }
2865 }
2866
2867 fn collect_local_names_from_stmt(&mut self, stmt: &Stmt) {
2868 match stmt {
2869 Stmt::Compound(c) => self.collect_local_names_recursive(c),
2870 Stmt::If { then_stmt, else_stmt, cond, .. } => {
2871 self.collect_local_names_from_expr(cond);
2872 self.collect_local_names_from_stmt(then_stmt);
2873 if let Some(es) = else_stmt {
2874 self.collect_local_names_from_stmt(es);
2875 }
2876 }
2877 Stmt::Switch { body, expr, .. } => {
2878 self.collect_local_names_from_expr(expr);
2879 self.collect_local_names_from_stmt(body);
2880 }
2881 Stmt::While { body, cond, .. } => {
2882 self.collect_local_names_from_expr(cond);
2883 self.collect_local_names_from_stmt(body);
2884 }
2885 Stmt::DoWhile { body, cond, .. } => {
2886 self.collect_local_names_from_stmt(body);
2887 self.collect_local_names_from_expr(cond);
2888 }
2889 Stmt::For { init, cond, step, body, .. } => {
2890 if let Some(i) = init {
2891 match i {
2892 ForInit::Decl(d) => self.collect_decl_names(d),
2893 ForInit::Expr(e) => self.collect_local_names_from_expr(e),
2894 }
2895 }
2896 if let Some(c) = cond { self.collect_local_names_from_expr(c); }
2897 if let Some(s) = step { self.collect_local_names_from_expr(s); }
2898 self.collect_local_names_from_stmt(body);
2899 }
2900 Stmt::Expr(Some(e), _) => self.collect_local_names_from_expr(e),
2901 Stmt::Return(Some(e), _) => self.collect_local_names_from_expr(e),
2902 Stmt::Label { stmt, .. } | Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => {
2903 self.collect_local_names_from_stmt(stmt);
2904 }
2905 _ => {}
2906 }
2907 }
2908
2909 fn collect_local_names_from_expr(&mut self, expr: &Expr) {
2910 if let ExprKind::StmtExpr(c) = &expr.kind {
2911 self.collect_local_names_recursive(c);
2912 }
2913 match &expr.kind {
2916 ExprKind::Binary { lhs, rhs, .. }
2917 | ExprKind::Assign { lhs, rhs, .. }
2918 | ExprKind::Comma { lhs, rhs } => {
2919 self.collect_local_names_from_expr(lhs);
2920 self.collect_local_names_from_expr(rhs);
2921 }
2922 ExprKind::Conditional { cond, then_expr, else_expr } => {
2923 self.collect_local_names_from_expr(cond);
2924 self.collect_local_names_from_expr(then_expr);
2925 self.collect_local_names_from_expr(else_expr);
2926 }
2927 ExprKind::Cast { expr: e, .. }
2928 | ExprKind::AddrOf(e) | ExprKind::Deref(e)
2929 | ExprKind::UnaryPlus(e) | ExprKind::UnaryMinus(e)
2930 | ExprKind::BitNot(e) | ExprKind::LogNot(e)
2931 | ExprKind::PreInc(e) | ExprKind::PreDec(e)
2932 | ExprKind::PostInc(e) | ExprKind::PostDec(e)
2933 | ExprKind::Sizeof(e)
2934 | ExprKind::Member { expr: e, .. } | ExprKind::PtrMember { expr: e, .. } => {
2935 self.collect_local_names_from_expr(e);
2936 }
2937 ExprKind::Call { func, args } => {
2938 self.collect_local_names_from_expr(func);
2939 for a in args { self.collect_local_names_from_expr(a); }
2940 }
2941 ExprKind::Index { expr: e, index } => {
2942 self.collect_local_names_from_expr(e);
2943 self.collect_local_names_from_expr(index);
2944 }
2945 _ => {}
2946 }
2947 }
2948
2949 fn collect_decl_types(&mut self, decl: &Declaration) {
2952 let base_type = self.decl_specs_to_rust(&decl.specs);
2953 for init_decl in &decl.declarators {
2954 if let Some(name) = init_decl.declarator.name {
2955 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2956 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2957 }
2958 }
2959 }
2960
2961 fn writeln(&mut self, s: &str) {
2963 self.buffer.push_str(s);
2964 self.buffer.push('\n');
2965 }
2966
2967 fn into_generated_code(self) -> GeneratedCode {
2969 GeneratedCode {
2970 code: self.buffer,
2971 incomplete_count: self.incomplete_count,
2972 unresolved_names: self.unresolved_names,
2973 used_libc_fns: self.used_libc_fns,
2974 codegen_errors: self.codegen_errors,
2975 }
2976 }
2977
2978 pub fn generate_macro(mut self, info: &MacroInferInfo) -> GeneratedCode {
2980 let name_str = self.interner.get(info.name);
2981
2982 for p in &info.params {
2984 self.current_local_names.insert(p.name);
2985 }
2986
2987 self.current_type_param_map = info.generic_type_params.iter()
2989 .filter(|(idx, _)| **idx >= 0)
2990 .filter_map(|(idx, generic_name)| {
2991 info.params.get(*idx as usize).map(|p| (p.name, generic_name.clone()))
2992 })
2993 .collect();
2994
2995 for (name, _) in &self.current_type_param_map {
2998 self.current_local_names.remove(name);
2999 }
3000
3001 self.current_literal_string_params = info.literal_string_params.iter()
3003 .filter_map(|&idx| info.params.get(idx).map(|p| p.name))
3004 .collect();
3005
3006 let generic_clause = self.build_generic_clause(info);
3008
3009 let params_with_types = self.build_param_list(info);
3012
3013 let return_type = self.get_return_type(info);
3015 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
3016
3017 if self.dump_types_for.as_deref() == Some(name_str) {
3019 self.dump_type_info(name_str, info, ¶ms_with_types, &return_type);
3020 }
3021
3022 let thx_param = if self.perl_threaded && info.is_thx_dependent {
3025 "my_perl: *mut PerlInterpreter"
3026 } else {
3027 ""
3028 };
3029
3030 let params_str = if thx_param.is_empty() {
3032 params_with_types.clone()
3033 } else if params_with_types.is_empty() {
3034 thx_param.to_string()
3035 } else {
3036 format!("{}, {}", thx_param, params_with_types)
3037 };
3038
3039 self.dump_ast_comment_for_expr(name_str, &info.parse_result);
3041
3042 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
3044 let generic_info = if !generic_clause.is_empty() { " [generic]" } else { "" };
3045 self.writeln(&format!("/// {}{}{} - macro function", name_str, thx_info, generic_info));
3046 self.writeln("#[inline]");
3047 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
3048
3049 self.writeln(&format!("pub unsafe fn {}{}({}) -> {} {{", name_str, generic_clause, params_str, return_type));
3051
3052 let needs_unsafe = info.has_unsafe_ops();
3054 let body_indent = if needs_unsafe { " " } else { " " };
3055
3056 if needs_unsafe {
3057 self.writeln(" unsafe {");
3058 }
3059
3060 match &info.parse_result {
3061 ParseResult::Expression(expr) => {
3062 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
3063 let mut syn_expr = self.build_syn_expr_with_type_hint(expr, Some(info), type_hint.as_deref());
3064
3065 if self.current_return_type.as_ref().is_some_and(|ut| ut.is_void()) {
3066 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
3067 self.writeln(&format!("{}{};", body_indent, s));
3068 } else if self.current_return_type.as_ref().is_some_and(|ut| ut.is_bool())
3069 && !self.is_bool_expr_with_dict(expr)
3070 && !crate::syn_codegen::is_bool_syn_expr(&syn_expr) {
3071 if self.is_pointer_expr_unified(expr, Some(info))
3072 || self.infer_expr_type_unified(expr, Some(info)).is_some_and(|ut| ut.is_pointer()) {
3073 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
3074 self.writeln(&format!("{}!({}).is_null()", body_indent, s));
3077 } else {
3078 syn_expr = crate::syn_codegen::wrap_as_bool(syn_expr);
3079 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
3080 self.writeln(&format!("{}{}", body_indent, s));
3081 }
3082 } else {
3083 syn_expr = self.cast_return_syn_expr_if_needed(expr, Some(info), syn_expr);
3084 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
3085 self.writeln(&format!("{}{}", body_indent, s));
3086 }
3087 }
3088 ParseResult::Statement(block_items) => {
3089 for item in block_items {
3090 if let BlockItem::Stmt(stmt) = item {
3091 let rust_stmt = self.stmt_to_rust(stmt, info);
3092 self.writeln(&format!("{}{}", body_indent, rust_stmt));
3093 }
3094 }
3095 }
3096 ParseResult::Unparseable(_) => {
3097 self.writeln(&format!("{}unimplemented!()", body_indent));
3098 }
3099 }
3100
3101 if needs_unsafe {
3102 self.writeln(" }");
3103 }
3104
3105 self.writeln("}");
3106 self.writeln("");
3107
3108 self.into_generated_code()
3109 }
3110
3111 fn build_generic_clause(&self, info: &MacroInferInfo) -> String {
3113 if info.generic_type_params.is_empty() {
3114 return String::new();
3115 }
3116
3117 let mut params: Vec<&String> = info.generic_type_params.values().collect();
3119 params.sort();
3120 params.dedup();
3121
3122 format!("<{}>", params.iter().map(|s| s.as_str()).collect::<Vec<_>>().join(", "))
3123 }
3124
3125 fn build_param_list(&mut self, info: &MacroInferInfo) -> String {
3129 let mut_params = collect_mut_params(&info.parse_result, &info.params);
3130 let mut parts = Vec::new();
3131 for (i, p) in info.params.iter().enumerate() {
3132 if info.generic_type_params.contains_key(&(i as i32)) {
3133 continue;
3134 }
3135 let name = escape_rust_keyword(self.interner.get(p.name));
3136 let ty = self.get_param_type(p, info, i);
3137 self.current_param_types.insert(p.name, UnifiedType::from_rust_str(&ty));
3139 let mut_prefix = if mut_params.contains(&p.name) { "mut " } else { "" };
3140 parts.push(format!("{}{}: {}", mut_prefix, name, ty));
3141 }
3142 parts.join(", ")
3143 }
3144
3145 fn get_param_type(&mut self, param: &MacroParam, info: &MacroInferInfo, param_index: usize) -> String {
3147 if let Some(generic_name) = info.generic_type_params.get(&(param_index as i32)) {
3149 return generic_name.clone();
3150 }
3151
3152 if info.literal_string_params.contains(¶m_index) {
3154 return "&str".to_string();
3155 }
3156
3157 let should_be_const = self.const_pointer_positions.contains(¶m_index);
3158
3159 if let Some(mut ty) = best_constraint_for_macro_param(info, param) {
3160 if should_be_const {
3161 ty.make_outer_pointer_const();
3162 } else if ty.has_outer_pointer() {
3163 ty.make_outer_pointer_mut();
3165 }
3166 return self.type_repr_to_rust(&ty);
3167 }
3168
3169 self.unknown_marker().to_string()
3170 }
3171
3172 fn get_return_type(&mut self, info: &MacroInferInfo) -> String {
3178 if let Some(generic_name) = info.generic_type_params.get(&-1) {
3180 return generic_name.clone();
3181 }
3182
3183 if self.is_bool_return {
3185 return "bool".to_string();
3186 }
3187
3188 match &info.parse_result {
3189 ParseResult::Expression(expr) => {
3190 if let Some(ty) = info.get_return_type() {
3191 let mut ty_str = self.type_repr_to_rust(ty);
3192 if ty_str != "()" {
3193 if ty_str.contains("*mut") {
3195 if let Some(expr_ut) = self.infer_expr_type(expr, info) {
3196 if expr_ut.is_const_pointer() {
3197 ty_str = ty_str.replace("*mut", "*const");
3198 }
3199 }
3200 }
3201 return ty_str;
3202 }
3203 if let Some(ut) = self.infer_expr_type(expr, info) {
3207 let s = ut.to_rust_string();
3208 if s != "()" {
3209 return s;
3210 }
3211 }
3212 return ty_str;
3214 }
3215 self.unknown_marker().to_string()
3216 }
3217 ParseResult::Statement(_) => "()".to_string(),
3218 ParseResult::Unparseable(_) => "()".to_string(),
3219 }
3220 }
3221
3222 fn type_repr_to_rust(&mut self, ty: &crate::type_repr::TypeRepr) -> String {
3226 let result = ty.to_rust_string(self.interner);
3227 let result = self.substitute_type_params(&result);
3228 if result.contains("/*") {
3229 self.incomplete_count += 1;
3230 }
3231 result
3232 }
3233
3234 fn substitute_type_params(&self, type_str: &str) -> String {
3236 if self.current_type_param_map.is_empty() {
3237 return type_str.to_string();
3238 }
3239 let mut result = type_str.to_string();
3240 for (param_name, generic_name) in &self.current_type_param_map {
3241 let name_str = self.interner.get(*param_name);
3242 result = replace_word(&result, name_str, generic_name);
3244 }
3245 result
3246 }
3247
3248 fn detect_mutable_ptr_pattern<'b>(&self, compound: &'b CompoundStmt) -> Option<&'b Expr> {
3253 if compound.items.len() != 2 {
3255 return None;
3256 }
3257
3258 let decl = match &compound.items[0] {
3260 BlockItem::Decl(d) => d,
3261 _ => return None,
3262 };
3263
3264 if decl.declarators.len() != 1 {
3266 return None;
3267 }
3268 let init_decl = &decl.declarators[0];
3269 let declared_name = init_decl.declarator.name?;
3270 let init = init_decl.init.as_ref()?;
3271
3272 let init_expr = match init {
3274 Initializer::Expr(e) => e.as_ref(),
3275 _ => return None,
3276 };
3277
3278 let last_expr = match &compound.items[1] {
3280 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => e,
3281 _ => return None,
3282 };
3283
3284 if let ExprKind::Ident(name) = &last_expr.kind {
3286 if *name == declared_name {
3287 return Some(init_expr);
3288 }
3289 }
3290
3291 None
3292 }
3293
3294 fn maybe_decay_flex_array(
3305 &self,
3306 access: syn::Expr,
3307 base: &Expr,
3308 member: InternedStr,
3309 info: Option<&MacroInferInfo>,
3310 is_ptr_member: bool,
3311 ) -> syn::Expr {
3312 let Some(fd) = self.fields_dict else { return access; };
3313 let Some(info) = info else { return access; };
3314 let Some(constraints) = info.type_env.expr_constraints.get(&base.id) else {
3315 return access;
3316 };
3317 let Some(base_type) = constraints.first().map(|c| &c.ty) else {
3318 return access;
3319 };
3320 let struct_name = if is_ptr_member {
3321 base_type.pointee_name()
3322 } else {
3323 base_type.type_name()
3324 };
3325 let Some(struct_name) = struct_name else { return access; };
3326 let Some(elem) = fd.flexible_array_element(struct_name, member) else {
3327 return access;
3328 };
3329 let elem_str = elem.to_rust_string(self.interner);
3331 let target_ty_str = format!("*mut {}", elem_str);
3332 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3333 attrs: vec![],
3334 and_token: Default::default(),
3335 raw: Default::default(),
3336 mutability: syn::PointerMutability::Const(Default::default()),
3337 expr: Box::new(access),
3338 });
3339 crate::syn_codegen::insert_cast(raw_const, crate::syn_codegen::parse_type(&target_ty_str))
3340 }
3341
3342 fn try_inline_call_for_addrof(&self, inner: &Expr) -> Option<Expr> {
3351 let (callee_id, args) = match &inner.kind {
3352 ExprKind::Call { func, args } => match &func.kind {
3353 ExprKind::Ident(name) => (*name, args),
3354 _ => return None,
3355 },
3356 _ => return None,
3357 };
3358
3359 let callee_info = self.macro_ctx.macros.get(&callee_id)?;
3360 let body = match &callee_info.parse_result {
3361 ParseResult::Expression(e) => e,
3362 _ => return None,
3363 };
3364
3365 if callee_info.is_thx_dependent {
3367 return None;
3368 }
3369 if callee_info.params.len() != args.len() {
3370 return None;
3371 }
3372
3373 let mut subs: HashMap<InternedStr, &Expr> = HashMap::new();
3375 for (param, arg) in callee_info.params.iter().zip(args.iter()) {
3376 subs.insert(param.name, arg);
3377 }
3378
3379 let mut inlined = (**body).clone();
3380 substitute_idents(&mut inlined, &subs);
3381 Some(inlined)
3382 }
3383
3384 fn build_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
3389 use crate::syn_codegen::*;
3390
3391 match &expr.kind {
3392 ExprKind::Ident(name) => {
3393 if let Some(subst) = self.param_substitutions.get(name) {
3395 return syn::parse_str(subst).unwrap_or_else(|_| int_lit(0));
3397 }
3398 let name_str = self.interner.get(*name);
3399 if LIBC_FUNCTIONS.contains(&name_str) {
3401 self.used_libc_fns.insert(name_str.to_string());
3402 }
3403 if !self.current_local_names.contains(name)
3405 && !self.enum_dict.is_enum_variant(*name)
3406 && !self.known_symbols.contains(name_str)
3407 {
3408 let s = name_str.to_string();
3409 if !self.unresolved_names.contains(&s) {
3410 self.unresolved_names.push(s);
3411 }
3412 }
3413 if name_str == "true" || name_str == "false" {
3415 return syn::Expr::Lit(syn::ExprLit {
3416 attrs: vec![],
3417 lit: syn::Lit::Bool(syn::LitBool {
3418 value: name_str == "true",
3419 span: proc_macro2::Span::call_site(),
3420 }),
3421 });
3422 }
3423 let escaped = escape_rust_keyword(name_str);
3424 if self.bindings_info.static_arrays.contains(name_str) {
3439 let elem = self.bindings_info.static_array_element_type(name_str)
3440 .unwrap_or_else(|| "u8".to_string());
3441 return syn::parse_str(&format!(
3442 "((&raw const {}) as *const {})",
3443 escaped, elem
3444 ))
3445 .unwrap_or_else(|_| int_lit(0));
3446 }
3447 syn::Expr::Path(syn::ExprPath {
3448 attrs: vec![],
3449 qself: None,
3450 path: ident(&escaped).into(),
3451 })
3452 }
3453 ExprKind::IntLit(n) => int_lit(*n),
3454 ExprKind::UIntLit(n) => {
3455 let lit = syn::LitInt::new(&format!("{}u64", n), proc_macro2::Span::call_site());
3456 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Int(lit) })
3457 }
3458 ExprKind::FloatLit(f) => {
3459 let lit = syn::LitFloat::new(&format!("{}", f), proc_macro2::Span::call_site());
3460 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Float(lit) })
3461 }
3462 ExprKind::CharLit(c) => {
3463 let s = if c.is_ascii() {
3464 format!("b'{}' as i8", escape_char(*c))
3465 } else {
3466 format!("0x{:02x}u8 as i8", c)
3467 };
3468 syn::parse_str(&s).unwrap_or_else(|_| int_lit(0))
3469 }
3470 ExprKind::StringLit(s) => {
3471 syn::parse_str(&format!("c\"{}\"", escape_string(s)))
3472 .unwrap_or_else(|_| int_lit(0))
3473 }
3474 ExprKind::Deref(inner) => {
3475 let e = self.build_syn_expr(inner, info);
3476 deref(e)
3477 }
3478 ExprKind::AddrOf(inner) => {
3479 if let Some(inlined) = self.try_inline_call_for_addrof(inner) {
3485 let e = self.build_syn_expr(&inlined, info);
3486 return addr_of_mut(e);
3487 }
3488 let e = self.build_syn_expr(inner, info);
3489 addr_of_mut(e)
3490 }
3491 ExprKind::UnaryPlus(inner) => {
3492 self.build_syn_expr(inner, info)
3493 }
3494 ExprKind::BitNot(inner) => {
3495 let e = self.build_syn_expr(inner, info);
3496 syn::Expr::Unary(syn::ExprUnary {
3497 attrs: vec![],
3498 op: syn::UnOp::Not(Default::default()),
3499 expr: Box::new(e),
3500 })
3501 }
3502 ExprKind::Member { expr: base, member } => {
3503 let e = self.build_syn_expr(base, info);
3504 let m = self.interner.get(*member);
3505 if self.is_bitfield_method(m) {
3506 syn::Expr::MethodCall(syn::ExprMethodCall {
3508 attrs: vec![],
3509 receiver: Box::new(e),
3510 dot_token: Default::default(),
3511 method: ident(m),
3512 turbofish: None,
3513 paren_token: Default::default(),
3514 args: syn::punctuated::Punctuated::new(),
3515 })
3516 } else {
3517 let access = field_access(e, m);
3518 self.maybe_decay_flex_array(access, base, *member, info, false)
3519 }
3520 }
3521 ExprKind::PtrMember { expr: base, member } => {
3522 let e = self.build_syn_expr(base, info);
3523 let m = self.interner.get(*member);
3524 let derefed = deref(e);
3525 if self.is_bitfield_method(m) {
3526 syn::Expr::MethodCall(syn::ExprMethodCall {
3527 attrs: vec![],
3528 receiver: Box::new(derefed),
3529 dot_token: Default::default(),
3530 method: ident(m),
3531 turbofish: None,
3532 paren_token: Default::default(),
3533 args: syn::punctuated::Punctuated::new(),
3534 })
3535 } else {
3536 let access = field_access(derefed, m);
3537 self.maybe_decay_flex_array(access, base, *member, info, true)
3538 }
3539 }
3540 ExprKind::Comma { lhs, rhs } => {
3541 let l = self.build_syn_expr(lhs, info);
3542 let r = self.build_syn_expr(rhs, info);
3543 if expr_yields_value_for_stmt_use(&l) {
3555 let l_str = expr_to_string(&l);
3556 let r_str = expr_to_string(&r);
3557 syn::parse_str(&format!("{{ let _ = {}; {} }}", l_str, r_str))
3558 .unwrap_or_else(|_| int_lit(0))
3559 } else {
3560 syn::Expr::Block(syn::ExprBlock {
3561 attrs: vec![],
3562 label: None,
3563 block: syn::Block {
3564 brace_token: Default::default(),
3565 stmts: vec![
3566 syn::Stmt::Expr(l, Some(Default::default())),
3567 syn::Stmt::Expr(r, None),
3568 ],
3569 },
3570 })
3571 }
3572 }
3573 ExprKind::UnaryMinus(inner) => {
3574 let e = self.build_syn_expr(inner, info);
3575 let e_str = expr_to_string(&e);
3577 if is_unsigned_cast_expr(&e_str) {
3578 return syn::parse_str(&format!("({}).wrapping_neg()", e_str.trim_start_matches('-')))
3579 .unwrap_or_else(|_| int_lit(0));
3580 }
3581 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
3582 let ts = ut.to_rust_string();
3583 if matches!(normalize_integer_type(&ts), Some("usize" | "u8" | "u16" | "u32" | "u64")) {
3584 self.codegen_errors.push(format!("cannot negate unsigned type: -({}: {})", e_str, ts));
3585 }
3586 }
3587 syn::Expr::Unary(syn::ExprUnary {
3588 attrs: vec![],
3589 op: syn::UnOp::Neg(Default::default()),
3590 expr: Box::new(e),
3591 })
3592 }
3593 ExprKind::LogNot(inner) => {
3594 if matches!(&inner.kind, ExprKind::StringLit(_)) {
3596 return syn::parse_str("false").unwrap_or_else(|_| int_lit(0));
3597 }
3598 let e = self.build_syn_expr(inner, info);
3599 if !self.is_bool_expr_with_dict(inner)
3600 && (self.is_pointer_expr_unified(inner, info)
3601 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()))
3602 {
3603 return syn::Expr::MethodCall(syn::ExprMethodCall {
3608 attrs: vec![],
3609 receiver: Box::new(e),
3610 dot_token: Default::default(),
3611 method: ident("is_null"),
3612 turbofish: None,
3613 paren_token: Default::default(),
3614 args: syn::punctuated::Punctuated::new(),
3615 });
3616 }
3617 let bool_e = if self.is_bool_expr_with_dict(inner) {
3618 e
3619 } else {
3620 wrap_as_bool(e)
3622 };
3623 syn::Expr::Unary(syn::ExprUnary {
3624 attrs: vec![],
3625 op: syn::UnOp::Not(Default::default()),
3626 expr: Box::new(bool_e),
3627 })
3628 }
3629 ExprKind::Cast { type_name, expr: inner } => {
3630 let t = self.type_name_to_rust(type_name);
3631 if is_unsigned_integer_target(&t) {
3635 if let ExprKind::UnaryMinus(minus_inner) = &inner.kind {
3636 if matches!(&minus_inner.kind,
3637 ExprKind::IntLit(1) | ExprKind::UIntLit(1))
3638 {
3639 return syn::parse_str(&format!("{}::MAX", t))
3640 .unwrap_or_else(|_| int_lit(0));
3641 }
3642 }
3643 }
3644 if (t.starts_with("*mut ") || t.starts_with("*const "))
3651 && matches!(&inner.kind, ExprKind::AddrOf(_))
3652 {
3653 if let ExprKind::AddrOf(addrof_inner) = &inner.kind {
3654 let inlined_owned;
3656 let inner_to_build: &Expr =
3657 if let Some(inlined) = self.try_inline_call_for_addrof(addrof_inner) {
3658 inlined_owned = inlined;
3659 &inlined_owned
3660 } else {
3661 addrof_inner
3662 };
3663 let inner_e = self.build_syn_expr(inner_to_build, info);
3664 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3665 attrs: vec![],
3666 and_token: Default::default(),
3667 raw: Default::default(),
3668 mutability: syn::PointerMutability::Const(Default::default()),
3669 expr: Box::new(inner_e),
3670 });
3671 return insert_cast(raw_const, parse_type(&t));
3672 }
3673 }
3674 let e = self.build_syn_expr(inner, info);
3675 if t == "()" {
3676 let e_str = expr_to_string(&e);
3683 return syn::parse_str(&format!("{{ let _ = {}; }}", e_str))
3684 .unwrap_or_else(|_| int_lit(0));
3685 }
3686 if t == "bool" {
3687 if self.is_bool_expr_with_dict(inner) {
3689 return e;
3690 }
3691 if self.is_pointer_expr_unified(inner, info)
3692 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()) {
3693 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3695 attrs: vec![],
3696 receiver: Box::new(e),
3697 dot_token: Default::default(),
3698 method: ident("is_null"),
3699 turbofish: None,
3700 paren_token: Default::default(),
3701 args: syn::punctuated::Punctuated::new(),
3702 });
3703 return syn::Expr::Unary(syn::ExprUnary {
3704 attrs: vec![],
3705 op: syn::UnOp::Not(Default::default()),
3706 expr: Box::new(is_null),
3707 });
3708 }
3709 return wrap_as_bool(e);
3710 }
3711 if self.is_enum_cast_target(type_name) {
3712 let e_str = expr_to_string(&e);
3714 return syn::parse_str(&format!("std::mem::transmute::<_, {}>({})", t, e_str))
3715 .unwrap_or_else(|_| int_lit(0));
3716 }
3717 insert_cast(e, parse_type(&t))
3718 }
3719 ExprKind::Sizeof(inner) => {
3720 if let ExprKind::Ident(name) = &inner.kind {
3722 if self.current_literal_string_params.contains(name) {
3723 let param = escape_rust_keyword(self.interner.get(*name));
3724 return syn::parse_str(&format!("({}.len() + 1)", param))
3725 .unwrap_or_else(|_| int_lit(0));
3726 }
3727 }
3728 let e = self.build_syn_expr(inner, info);
3729 let e_str = expr_to_string(&e);
3730 syn::parse_str(&format!("std::mem::size_of_val(&({}))", e_str))
3735 .unwrap_or_else(|_| int_lit(0))
3736 }
3737 ExprKind::SizeofType(type_name) => {
3738 let t = self.type_name_to_rust(type_name);
3739 syn::parse_str(&format!("std::mem::size_of::<{}>()", t))
3740 .unwrap_or_else(|_| int_lit(0))
3741 }
3742 ExprKind::Index { expr: base, index } => {
3743 use crate::syn_codegen::*;
3744 let i = self.build_syn_expr(index, info);
3745 let i_isize = cast_syn_expr(i, "isize");
3746 let base_expr: syn::Expr = if self.is_array_like_expr(base, info) {
3747 let raw_ptr_expr: syn::Expr = if let ExprKind::Ident(n) = &base.kind {
3753 let name_str = self.interner.get(*n);
3754 let escaped = escape_rust_keyword(name_str);
3755 if self.bindings_info.static_arrays.contains(name_str) {
3756 let elem = self.bindings_info
3757 .static_array_element_type(name_str)
3758 .unwrap_or_else(|| "u8".to_string());
3759 syn::parse_str(&format!(
3760 "((&raw const {}) as *const {})",
3761 escaped, elem
3762 ))
3763 .unwrap_or_else(|_| int_lit(0))
3764 } else {
3765 let id = ident_expr(escaped.as_str());
3766 method_call(id, "as_ptr", vec![])
3767 }
3768 } else {
3769 let b = self.build_syn_expr(base, info);
3770 method_call(b, "as_ptr", vec![])
3771 };
3772 let elem_str = self.infer_expr_type_unified(base, info)
3776 .and_then(|ut| ut.inner_type().cloned())
3777 .map(|inner| inner.to_rust_string());
3778 if let Some(elem) = elem_str {
3779 cast_syn_expr(raw_ptr_expr, &format!("*mut {}", elem))
3780 } else {
3781 raw_ptr_expr
3782 }
3783 } else {
3784 self.build_syn_expr(base, info)
3785 };
3786 let offset_call = method_call(base_expr, "offset", vec![i_isize]);
3787 deref(offset_call)
3788 }
3789 ExprKind::Conditional { cond, then_expr, else_expr } => {
3790 let c = self.build_syn_expr(cond, info);
3791 let c_str = expr_to_string(&c);
3792 let cond_str = self.wrap_as_bool_condition(cond, &c_str, info);
3793 let cond_syn: syn::Expr = syn::parse_str(&cond_str).unwrap_or(c);
3794
3795 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
3796 let tt = self.infer_expr_type_unified(then_expr, info);
3797 let et = self.infer_expr_type_unified(else_expr, info);
3798
3799 if let Some(ref hint) = type_hint {
3801 let hint_ut = UnifiedType::from_rust_str(hint);
3802 if hint_ut.is_pointer() {
3803 if is_null_literal(else_expr)
3810 && tt.as_ref().map_or(true, |t| t.is_pointer())
3811 {
3812 let t = self.build_syn_expr(then_expr, info);
3813 let e: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3814 .unwrap_or_else(|_| int_lit(0));
3815 return if_else(cond_syn, t, e);
3816 }
3817 if is_null_literal(then_expr)
3818 && et.as_ref().map_or(true, |t| t.is_pointer())
3819 {
3820 let t: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3821 .unwrap_or_else(|_| int_lit(0));
3822 let e = self.build_syn_expr(else_expr, info);
3823 return if_else(cond_syn, t, e);
3824 }
3825 }
3826 if normalize_integer_type(hint).is_some() {
3829 if is_null_literal(else_expr) {
3830 let t = self.build_syn_expr(then_expr, info);
3831 return if_else(cond_syn, t, int_lit(0));
3832 }
3833 if is_null_literal(then_expr) {
3834 let e = self.build_syn_expr(else_expr, info);
3835 return if_else(cond_syn, int_lit(0), e);
3836 }
3837 }
3838 if hint_ut.is_bool() {
3839 let then_syn = match &then_expr.kind {
3840 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3841 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3842 _ => self.build_syn_expr(then_expr, info),
3843 };
3844 let else_syn = match &else_expr.kind {
3845 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3846 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3847 _ => self.build_syn_expr(else_expr, info),
3848 };
3849 return if_else(cond_syn, then_syn, else_syn);
3850 }
3851 }
3852
3853 let then_syn = if is_null_literal(then_expr) {
3855 if let Some(ref eut) = et {
3856 if eut.is_pointer() {
3857 syn::parse_str(&null_ptr_expr(eut)).unwrap_or_else(|_| int_lit(0))
3858 } else { self.build_syn_expr(then_expr, info) }
3859 } else { self.build_syn_expr(then_expr, info) }
3860 } else { self.build_syn_expr(then_expr, info) };
3861
3862 let else_syn = if is_null_literal(else_expr) {
3863 if let Some(ref tut) = tt {
3864 if tut.is_pointer() {
3865 syn::parse_str(&null_ptr_expr(tut)).unwrap_or_else(|_| int_lit(0))
3866 } else { self.build_syn_expr(else_expr, info) }
3867 } else { self.build_syn_expr(else_expr, info) }
3868 } else { self.build_syn_expr(else_expr, info) };
3869
3870 if let (Some(tut), Some(eut)) = (&tt, &et) {
3872 let ts = tut.to_rust_string();
3873 let es = eut.to_rust_string();
3874 if let (Some(tn), Some(en)) = (normalize_integer_type(&ts), normalize_integer_type(&es)) {
3875 if tn != en {
3876 if let Some(wider) = wider_integer_type(&ts, &es) {
3877 let (then_final, else_final) = if normalize_integer_type(&ts) != Some(wider) {
3878 (cast_syn_expr(then_syn, wider), else_syn)
3879 } else {
3880 (then_syn, cast_syn_expr(else_syn, wider))
3881 };
3882 return if_else(cond_syn, then_final, else_final);
3883 }
3884 }
3885 }
3886 if tut.is_pointer() && eut.is_pointer() && ts != es
3889 && is_sv_subtype_cast(tut, eut)
3890 {
3891 let target_str = type_hint.as_deref()
3894 .filter(|t| *t != "()" && !UnifiedType::from_rust_str(t).is_void())
3895 .unwrap_or(&ts)
3896 .to_string();
3897 return if_else(
3898 cond_syn,
3899 cast_syn_expr(then_syn, &target_str),
3900 cast_syn_expr(else_syn, &target_str),
3901 );
3902 }
3903 }
3904
3905 if_else(cond_syn, then_syn, else_syn)
3906 }
3907 ExprKind::Binary { op, lhs, rhs } => {
3908 if *op == BinOp::Sub {
3910 if let ExprKind::Sizeof(inner) = &lhs.kind {
3911 if let ExprKind::Ident(name) = &inner.kind {
3912 if self.current_literal_string_params.contains(name) {
3913 if let ExprKind::IntLit(1) = &rhs.kind {
3914 let param = escape_rust_keyword(self.interner.get(*name));
3915 return syn::parse_str(&format!("{}.len()", param))
3916 .unwrap_or_else(|_| int_lit(0));
3917 }
3918 }
3919 }
3920 }
3921 }
3922
3923 if matches!(op, BinOp::Eq | BinOp::Ne) {
3926 let s_eq = |s: &ExprKind| matches!(s, ExprKind::StringLit(_));
3927 let lhs_is_str = s_eq(&lhs.kind);
3928 let rhs_is_str = s_eq(&rhs.kind);
3929 if (lhs_is_str && is_null_literal(rhs))
3930 || (rhs_is_str && is_null_literal(lhs))
3931 {
3932 return syn::parse_str(
3933 if *op == BinOp::Eq { "false" } else { "true" }
3934 ).unwrap_or_else(|_| int_lit(0));
3935 }
3936 }
3937 if matches!(op, BinOp::Eq | BinOp::Ne) {
3941 let opt_lhs = (is_null_literal(rhs) || matches!(&rhs.kind, ExprKind::IntLit(0)))
3942 && self.is_option_fn_pointer_expr(lhs, info);
3943 let opt_rhs = (is_null_literal(lhs) || matches!(&lhs.kind, ExprKind::IntLit(0)))
3944 && self.is_option_fn_pointer_expr(rhs, info);
3945 if opt_lhs || opt_rhs {
3946 let receiver_expr = if opt_lhs { lhs } else { rhs };
3947 let r = self.build_syn_expr(receiver_expr, info);
3948 let method = if *op == BinOp::Eq { "is_none" } else { "is_some" };
3949 return syn::Expr::MethodCall(syn::ExprMethodCall {
3950 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3951 method: ident(method), turbofish: None,
3952 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3953 });
3954 }
3955 }
3956 if matches!(op, BinOp::Eq | BinOp::Ne) {
3958 if is_null_literal(rhs) {
3959 if self.is_pointer_expr_unified(lhs, info)
3960 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer()) {
3961 let l = self.build_syn_expr(lhs, info);
3962 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3963 attrs: vec![], receiver: Box::new(l), dot_token: Default::default(),
3964 method: ident("is_null"), turbofish: None,
3965 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3966 });
3967 return if *op == BinOp::Eq { is_null } else {
3968 syn::Expr::Unary(syn::ExprUnary {
3969 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3970 expr: Box::new(is_null),
3971 })
3972 };
3973 }
3974 }
3975 if is_null_literal(lhs) {
3976 if self.is_pointer_expr_unified(rhs, info)
3977 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer()) {
3978 let r = self.build_syn_expr(rhs, info);
3979 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3980 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3981 method: ident("is_null"), turbofish: None,
3982 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3983 });
3984 return if *op == BinOp::Eq { is_null } else {
3985 syn::Expr::Unary(syn::ExprUnary {
3986 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3987 expr: Box::new(is_null),
3988 })
3989 };
3990 }
3991 }
3992 if self.is_bool_expr_with_dict(lhs) {
3994 match (&rhs.kind, op) {
3995 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
3996 return self.build_syn_expr(lhs, info);
3997 }
3998 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
3999 let l = self.build_syn_expr(lhs, info);
4000 return syn::Expr::Unary(syn::ExprUnary {
4001 attrs: vec![], op: syn::UnOp::Not(Default::default()),
4002 expr: Box::new(l),
4003 });
4004 }
4005 _ => {}
4006 }
4007 }
4008 if self.is_bool_expr_with_dict(rhs) {
4009 match (&lhs.kind, op) {
4010 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
4011 return self.build_syn_expr(rhs, info);
4012 }
4013 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
4014 let r = self.build_syn_expr(rhs, info);
4015 return syn::Expr::Unary(syn::ExprUnary {
4016 attrs: vec![], op: syn::UnOp::Not(Default::default()),
4017 expr: Box::new(r),
4018 });
4019 }
4020 _ => {}
4021 }
4022 }
4023 }
4024
4025 if matches!(op, BinOp::Add | BinOp::Sub) {
4027 let l_arr = !self.is_static_array_expr(lhs)
4032 && self.is_array_like_expr(lhs, info);
4033 let r_arr = !self.is_static_array_expr(rhs)
4034 && self.is_array_like_expr(rhs, info);
4035 let lp = l_arr
4036 || self.is_static_array_expr(lhs)
4037 || self.is_pointer_expr_unified(lhs, info)
4038 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
4039 let rp = r_arr
4040 || self.is_static_array_expr(rhs)
4041 || self.is_pointer_expr_unified(rhs, info)
4042 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
4043 let l_is_static_arr = self.is_static_array_expr(lhs);
4050 let r_is_static_arr = self.is_static_array_expr(rhs);
4051 let cast_to_mut = |this: &mut Self, expr: syn::Expr, arr_expr: &Expr,
4052 needs_as_ptr: bool| -> syn::Expr {
4053 let elem = this.infer_expr_type_unified(arr_expr, info)
4054 .and_then(|ut| ut.inner_type().cloned())
4055 .map(|u| u.to_rust_string());
4056 let base = if needs_as_ptr {
4057 crate::syn_codegen::method_call(expr, "as_ptr", vec![])
4058 } else {
4059 expr
4060 };
4061 if let Some(e) = elem {
4062 crate::syn_codegen::cast_syn_expr(base, &format!("*mut {}", e))
4063 } else {
4064 base
4065 }
4066 };
4067 if lp && !rp {
4068 let l = self.build_syn_expr(lhs, info);
4069 let l = if l_arr {
4070 cast_to_mut(self, l, lhs, true)
4071 } else if l_is_static_arr {
4072 cast_to_mut(self, l, lhs, false)
4073 } else {
4074 l
4075 };
4076 let r = self.build_syn_expr(rhs, info);
4077 let r_isize = crate::syn_codegen::cast_syn_expr(r, "isize");
4078 let arg = if *op == BinOp::Add { r_isize } else {
4079 syn::Expr::Unary(syn::ExprUnary {
4080 attrs: vec![],
4081 op: syn::UnOp::Neg(Default::default()),
4082 expr: Box::new(r_isize),
4083 })
4084 };
4085 return crate::syn_codegen::method_call(l, "offset", vec![arg]);
4086 }
4087 if rp && !lp && *op == BinOp::Add {
4088 let l = self.build_syn_expr(lhs, info);
4089 let r = self.build_syn_expr(rhs, info);
4090 let r = if r_arr {
4091 cast_to_mut(self, r, rhs, true)
4092 } else if r_is_static_arr {
4093 cast_to_mut(self, r, rhs, false)
4094 } else {
4095 r
4096 };
4097 let l_isize = crate::syn_codegen::cast_syn_expr(l, "isize");
4098 return crate::syn_codegen::method_call(r, "offset", vec![l_isize]);
4099 }
4100 if lp && rp && *op == BinOp::Sub {
4101 let l = self.build_syn_expr(lhs, info);
4102 let r = self.build_syn_expr(rhs, info);
4103 return crate::syn_codegen::method_call(l, "offset_from", vec![r]);
4104 }
4105 }
4106
4107 if matches!(&rhs.kind, ExprKind::IntLit(_)) {
4109 if let Some(lut) = self.infer_expr_type_unified(lhs, info) {
4110 if lut.is_float() {
4111 if let ExprKind::IntLit(v) = &rhs.kind {
4112 let l = self.build_syn_expr(lhs, info);
4113 let l_str = expr_to_string(&l);
4114 return syn::parse_str(&format!("{} {} {}.0", l_str, bin_op_to_rust(*op), v))
4115 .unwrap_or_else(|_| int_lit(0));
4116 }
4117 }
4118 }
4119 }
4120 if matches!(&lhs.kind, ExprKind::IntLit(_)) {
4121 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4122 if rut.is_float() {
4123 if let ExprKind::IntLit(v) = &lhs.kind {
4124 let r = self.build_syn_expr(rhs, info);
4125 let r_str = expr_to_string(&r);
4126 return syn::parse_str(&format!("{}.0 {} {}", v, bin_op_to_rust(*op), r_str))
4127 .unwrap_or_else(|_| int_lit(0));
4128 }
4129 }
4130 }
4131 }
4132
4133 if matches!(op, BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Eq | BinOp::Ne) {
4138 if let (Some(lut), Some(rut)) =
4139 (self.infer_expr_type_unified(lhs, info),
4140 self.infer_expr_type_unified(rhs, info))
4141 {
4142 if lut.is_pointer() && rut.is_pointer()
4143 && pointer_inner_compatible(&lut, &rut)
4144 && (lut.is_const_pointer() != rut.is_const_pointer()
4145 || lut.to_rust_string() != rut.to_rust_string())
4146 {
4147 let l = self.build_syn_expr(lhs, info);
4148 let r = self.build_syn_expr(rhs, info);
4149 let target = lut.to_rust_string();
4150 return syn::Expr::Binary(syn::ExprBinary {
4151 attrs: vec![], left: Box::new(l),
4152 op: crate::syn_codegen::to_syn_binop(*op),
4153 right: Box::new(crate::syn_codegen::cast_syn_expr(r, &target)),
4154 });
4155 }
4156 }
4157 }
4158
4159 let l = self.build_syn_expr(lhs, info);
4160 let r = self.build_syn_expr(rhs, info);
4161
4162 if matches!(op, BinOp::LogAnd | BinOp::LogOr) {
4164 let l_str = expr_to_string(&l);
4165 let r_str = expr_to_string(&r);
4166 let l_bool = self.wrap_as_bool_condition(lhs, &l_str, info);
4167 let r_bool = self.wrap_as_bool_condition(rhs, &r_str, info);
4168 let l_syn: syn::Expr = syn::parse_str(&l_bool).unwrap_or(l);
4169 let r_syn: syn::Expr = syn::parse_str(&r_bool).unwrap_or(r);
4170 return syn::Expr::Binary(syn::ExprBinary {
4171 attrs: vec![], left: Box::new(l_syn),
4172 op: crate::syn_codegen::to_syn_binop(*op),
4173 right: Box::new(r_syn),
4174 });
4175 }
4176
4177 let lt = self.infer_expr_type_unified(lhs, info);
4179 let rt = self.infer_expr_type_unified(rhs, info);
4180
4181 let make_binary_op = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4185 syn::Expr::Binary(syn::ExprBinary {
4186 attrs: vec![], left: Box::new(left),
4187 op: crate::syn_codegen::to_syn_binop(*op),
4188 right: Box::new(right),
4189 })
4190 };
4191 match (<, &rt) {
4192 (Some(lut), None) if self.is_rust_enum_type(lut) => {
4193 return make_binary_op(cast_syn_expr(l, "u32"), r);
4194 }
4195 (None, Some(rut)) if self.is_rust_enum_type(rut) => {
4196 return make_binary_op(l, cast_syn_expr(r, "u32"));
4197 }
4198 _ => {}
4199 }
4200
4201 if let (Some(lut), Some(rut)) = (<, &rt) {
4202 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4203 syn::Expr::Binary(syn::ExprBinary {
4204 attrs: vec![], left: Box::new(left),
4205 op: crate::syn_codegen::to_syn_binop(*op),
4206 right: Box::new(right),
4207 })
4208 };
4209 let l_is_enum = self.is_rust_enum_type(lut);
4212 let r_is_enum = self.is_rust_enum_type(rut);
4213 if l_is_enum && !r_is_enum {
4214 let rs = rut.to_rust_string();
4215 let target = normalize_integer_type(&rs).unwrap_or("u32");
4216 return make_binary(cast_syn_expr(l, target), r);
4217 }
4218 if r_is_enum && !l_is_enum {
4219 let ls = lut.to_rust_string();
4220 let target = normalize_integer_type(&ls).unwrap_or("u32");
4221 return make_binary(l, cast_syn_expr(r, target));
4222 }
4223 if rut.is_bool() {
4225 let ls = lut.to_rust_string();
4226 if let Some(nl) = normalize_integer_type(&ls) {
4227 return make_binary(l, cast_syn_expr(r, nl));
4228 }
4229 }
4230 if lut.is_bool() {
4231 let rs = rut.to_rust_string();
4232 if let Some(nr) = normalize_integer_type(&rs) {
4233 return make_binary(cast_syn_expr(l, nr), r);
4234 }
4235 }
4236 if lut.is_float() && !rut.is_float() {
4238 let ls = lut.to_rust_string();
4239 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4240 return make_binary(l, cast_syn_expr(r, float_ty));
4241 }
4242 if rut.is_float() && !lut.is_float() {
4243 let rs = rut.to_rust_string();
4244 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4245 return make_binary(cast_syn_expr(l, float_ty), r);
4246 }
4247 let ls = lut.to_rust_string();
4249 let rs = rut.to_rust_string();
4250 if let Some(wider) = wider_integer_type(&ls, &rs) {
4251 if normalize_integer_type(&ls) != Some(wider) {
4252 return make_binary(cast_syn_expr(l, wider), r);
4253 } else {
4254 return make_binary(l, cast_syn_expr(r, wider));
4255 }
4256 }
4257 }
4258 {
4260 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4261 syn::Expr::Binary(syn::ExprBinary {
4262 attrs: vec![], left: Box::new(left),
4263 op: crate::syn_codegen::to_syn_binop(*op),
4264 right: Box::new(right),
4265 })
4266 };
4267 match (<, &rt) {
4268 (Some(lut), None) if lut.is_float() => {
4269 let ls = lut.to_rust_string();
4270 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4271 return make_binary(l, cast_syn_expr(r, float_ty));
4272 }
4273 (None, Some(rut)) if rut.is_float() => {
4274 let rs = rut.to_rust_string();
4275 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4276 return make_binary(cast_syn_expr(l, float_ty), r);
4277 }
4278 _ => {}
4279 }
4280 if matches!(op, BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor) {
4282 match (<, &rt) {
4283 (Some(lut), None) => {
4284 let ls = lut.to_rust_string();
4285 if let Some(nl) = normalize_integer_type(&ls) {
4286 return make_binary(l, cast_syn_expr(r, nl));
4287 }
4288 }
4289 (None, Some(rut)) => {
4290 let rs = rut.to_rust_string();
4291 if let Some(nr) = normalize_integer_type(&rs) {
4292 return make_binary(cast_syn_expr(l, nr), r);
4293 }
4294 }
4295 _ => {}
4296 }
4297 }
4298 }
4299 syn::Expr::Binary(syn::ExprBinary {
4301 attrs: vec![],
4302 left: Box::new(l),
4303 op: crate::syn_codegen::to_syn_binop(*op),
4304 right: Box::new(r),
4305 })
4306 }
4307 ExprKind::Call { func, args } => {
4308 if let Some(syn_call) = self.try_build_common_macro_fn_call(func, args, info) {
4312 return syn_call;
4313 }
4314 if let ExprKind::Ident(name) = &func.kind {
4316 let func_name = self.interner.get(*name);
4317 if func_name == "__builtin_expect" && !args.is_empty() {
4319 return self.build_syn_expr(&args[0], info);
4320 }
4321 if func_name == "__builtin_unreachable" {
4323 return syn::parse_str("std::hint::unreachable_unchecked()").unwrap();
4324 }
4325 if (func_name == "__builtin_ctz" || func_name == "__builtin_ctzl") && args.len() == 1 {
4327 let arg = self.build_syn_expr(&args[0], info);
4328 return syn::Expr::MethodCall(syn::ExprMethodCall {
4329 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4330 method: ident("trailing_zeros"), turbofish: None,
4331 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4332 });
4333 }
4334 if (func_name == "__builtin_clz" || func_name == "__builtin_clzl") && args.len() == 1 {
4335 let arg = self.build_syn_expr(&args[0], info);
4336 return syn::Expr::MethodCall(syn::ExprMethodCall {
4337 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4338 method: ident("leading_zeros"), turbofish: None,
4339 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4340 });
4341 }
4342 if matches!(func_name, "ASSERT_IS_LITERAL" | "ASSERT_IS_PTR" | "ASSERT_NOT_PTR")
4344 && args.len() == 1
4345 {
4346 return self.build_syn_expr(&args[0], info);
4347 }
4348 if matches!(func_name, "offsetof" | "__builtin_offsetof") && args.len() == 2 {
4357 let type_name_str = if let ExprKind::Ident(name) = &args[0].kind {
4358 escape_rust_keyword(self.interner.get(*name)).to_string()
4359 } else {
4360 let s = self.build_syn_expr(&args[0], info);
4361 expr_to_string(&s)
4362 };
4363 if let Some(field_path) = self.expr_to_field_path(&args[1]) {
4364 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_name_str, field_path))
4365 .unwrap_or_else(|_| int_lit(0));
4366 }
4367 }
4368 }
4369
4370 let f_syn = self.build_syn_expr(func, info);
4372 let f_str = expr_to_string(&f_syn);
4373
4374 let callee_name = if let ExprKind::Ident(name) = &func.kind { Some(*name) } else { None };
4375 let needs_my_perl = callee_name
4376 .map(|name| self.needs_my_perl_for_call(name, args.len()))
4377 .unwrap_or(false);
4378
4379 let callee_generics = callee_name
4381 .and_then(|name| self.get_callee_generic_params(name).cloned());
4382
4383 if let Some(ref generics) = callee_generics {
4384 let mut type_args = Vec::new();
4386 let mut value_args: Vec<String> = if needs_my_perl {
4387 vec!["my_perl".to_string()]
4388 } else { vec![] };
4389 let mut value_idx = if needs_my_perl { 1usize } else { 0 };
4390 for (i, arg) in args.iter().enumerate() {
4391 if generics.contains_key(&(i as i32)) {
4392 let syn_arg = self.build_syn_expr(arg, info);
4393 type_args.push(normalize_parens(&expr_to_string(&syn_arg)));
4394 } else {
4395 value_args.push(self.build_arg_string_unified(arg, info, callee_name, value_idx));
4396 value_idx += 1;
4397 }
4398 }
4399 return syn::parse_str(&format!("{}::<{}>({})", f_str, type_args.join(", "), value_args.join(", ")))
4400 .unwrap_or_else(|_| int_lit(0));
4401 }
4402
4403 let mut arg_strs: Vec<String> = if needs_my_perl {
4405 vec!["my_perl".to_string()]
4406 } else { vec![] };
4407 let arg_offset = if needs_my_perl { 1usize } else { 0 };
4408 for (i, arg) in args.iter().enumerate() {
4409 arg_strs.push(self.build_arg_string_unified(arg, info, callee_name, i + arg_offset));
4410 }
4411 syn::parse_str(&format!("{}({})", f_str, arg_strs.join(", ")))
4412 .unwrap_or_else(|_| int_lit(0))
4413 }
4414 ExprKind::MacroCall { name, args, expanded, .. } => {
4415 if self.should_emit_as_macro_call(*name) {
4416 let name_str = escape_rust_keyword(self.interner.get(*name));
4417 let needs_my_perl = self.needs_my_perl_for_call(*name, args.len());
4418 let mut a: Vec<String> = if needs_my_perl {
4419 vec!["my_perl".to_string()]
4420 } else { vec![] };
4421 for arg in args {
4422 let arg_str = expr_to_string(&self.build_syn_expr(arg, info));
4423 a.push(normalize_parens(&arg_str));
4424 }
4425 syn::parse_str(&format!("{}({})", name_str, a.join(", ")))
4426 .unwrap_or_else(|_| int_lit(0))
4427 } else {
4428 self.build_syn_expr(expanded, info)
4429 }
4430 }
4431 ExprKind::BuiltinCall { name, args } => {
4432 let func_name = self.interner.get(*name);
4433 if matches!(func_name, "offsetof" | "__builtin_offsetof" | "STRUCT_OFFSET")
4434 && args.len() == 2
4435 {
4436 let type_str = match &args[0] {
4437 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4438 crate::ast::BuiltinArg::Expr(e) => {
4439 let s = self.build_syn_expr(e, info);
4440 expr_to_string(&s)
4441 }
4442 };
4443 let field_expr = match &args[1] {
4444 crate::ast::BuiltinArg::Expr(e) => self.expr_to_field_path(e),
4445 _ => None,
4446 };
4447 if let Some(fp) = field_expr {
4448 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_str, fp))
4449 .unwrap_or_else(|_| int_lit(0));
4450 }
4451 }
4452 let a: Vec<String> = args.iter().map(|arg| match arg {
4454 crate::ast::BuiltinArg::Expr(e) => {
4455 let s = self.build_syn_expr(e, info);
4456 expr_to_string(&s)
4457 }
4458 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4459 }).collect();
4460 syn::parse_str(&format!("{}({})", func_name, a.join(", ")))
4461 .unwrap_or_else(|_| int_lit(0))
4462 }
4463 ExprKind::Assign { op, lhs, rhs } => {
4464 self.build_assign_syn_expr(*op, lhs, rhs, info)
4465 }
4466 ExprKind::PreInc(inner) => {
4467 self.build_inc_dec_syn_expr(inner, info, true, false)
4468 }
4469 ExprKind::PreDec(inner) => {
4470 self.build_inc_dec_syn_expr(inner, info, false, false)
4471 }
4472 ExprKind::PostInc(inner) => {
4473 self.build_inc_dec_syn_expr(inner, info, true, true)
4474 }
4475 ExprKind::PostDec(inner) => {
4476 self.build_inc_dec_syn_expr(inner, info, false, true)
4477 }
4478 ExprKind::Assert { kind, condition } => {
4479 let assert_str = if let Some((real_cond, msg)) = decompose_assert_with_message(condition) {
4480 let c = self.build_syn_expr(real_cond, info);
4481 let c_str = expr_to_string(&c);
4482 let cond_str = self.wrap_as_bool_condition(real_cond, &c_str, info);
4483 format!("assert!({}, \"{}\")", normalize_parens(&cond_str), msg)
4484 } else {
4485 let c = self.build_syn_expr(condition, info);
4486 let c_str = expr_to_string(&c);
4487 if is_boolean_expr(condition) || self.is_bool_expr_with_dict(condition) {
4488 format!("assert!({})", normalize_parens(&c_str))
4489 } else if self.is_pointer_expr_unified(condition, info)
4490 || self.infer_expr_type_unified(condition, info).is_some_and(|ut| ut.is_pointer()) {
4491 format!("assert!(!({}).is_null())", c_str)
4495 } else {
4496 format!("assert!({} != 0)", normalize_parens(&c_str))
4497 }
4498 };
4499 let result = match kind {
4500 AssertKind::Assert => assert_str,
4501 AssertKind::AssertUnderscore => format!("{{ {}; }}", assert_str),
4502 };
4503 syn::parse_str(&result).unwrap_or_else(|_| int_lit(0))
4504 }
4505 ExprKind::StmtExpr(compound) => {
4506 if let Some(init_expr) = self.detect_mutable_ptr_pattern(compound) {
4508 return self.build_syn_expr(init_expr, info);
4509 }
4510 let mut parts: Vec<String> = Vec::new();
4514 for item in &compound.items {
4515 match item {
4516 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => {
4517 parts.push(self.build_expr_string(e, info));
4518 }
4519 BlockItem::Stmt(stmt) => {
4520 let s = match info {
4521 Some(info) => self.stmt_to_rust(stmt, info),
4522 None => self.stmt_to_rust_inline(stmt, ""),
4523 };
4524 parts.push(s);
4525 }
4526 BlockItem::Decl(decl) => {
4527 self.collect_decl_types(decl);
4528 let decl_str = self.decl_to_rust_let(decl, "");
4529 for line in decl_str.lines() {
4530 let trimmed = line.trim();
4531 if !trimmed.is_empty() {
4532 parts.push(trimmed.strip_suffix(';').unwrap_or(trimmed).to_string());
4533 }
4534 }
4535 }
4536 }
4537 }
4538 let block_str = if parts.is_empty() {
4539 "{ }".to_string()
4540 } else if parts.len() == 1 {
4541 parts.pop().unwrap()
4542 } else {
4543 let last = parts.pop().unwrap();
4544 let stmts = parts.join("; ");
4545 format!("{{ {}; {} }}", stmts, last)
4546 };
4547 syn::parse_str(&block_str).unwrap_or_else(|_| int_lit(0))
4548 }
4549 ExprKind::Alignof(ty) => {
4550 let ty_str = self.type_name_to_rust(ty);
4551 syn::parse_str(&format!("std::mem::align_of::<{}>()", ty_str))
4552 .unwrap_or_else(|_| int_lit(0))
4553 }
4554 _ => {
4558 self.codegen_errors.push(format!(
4559 "unhandled ExprKind in syn codegen: {:?}",
4560 std::mem::discriminant(&expr.kind)
4561 ));
4562 int_lit(0)
4563 }
4564 }
4565 }
4566
4567 fn build_arg_string_unified(&mut self, arg: &Expr, info: Option<&MacroInferInfo>,
4571 callee: Option<InternedStr>, arg_index: usize) -> String {
4572 if info.is_some() {
4574 if let Some(name) = self.find_literal_string_ident(arg) {
4575 if let Some(callee_name) = callee {
4576 if self.callee_expects_literal_string(callee_name, arg_index) {
4577 return escape_rust_keyword(self.interner.get(*name));
4578 }
4579 }
4580 let param = escape_rust_keyword(self.interner.get(*name));
4581 return format!("{}.as_ptr() as *const c_char", param);
4582 }
4583 }
4584 if is_null_literal(arg) {
4586 if let Some(callee_name) = callee {
4587 let func_name = self.interner.get(callee_name).to_string();
4588 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4589 if expected_ut.is_pointer() {
4590 return null_ptr_expr(&expected_ut);
4591 }
4592 }
4593 }
4594 }
4595 if let Some(callee_name) = callee {
4597 let func_name = self.interner.get(callee_name);
4598 if self.callee_param_is_bool(func_name, arg_index) {
4599 match &arg.kind {
4600 ExprKind::IntLit(0) => return "false".to_string(),
4601 ExprKind::IntLit(1) => return "true".to_string(),
4602 _ => {}
4603 }
4604 }
4605 }
4606 let mut syn_expr = self.build_syn_expr(arg, info);
4608 if let Some(callee_name) = callee {
4611 let func_name = self.interner.get(callee_name).to_string();
4612 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4613 let actual_ut = self.infer_expr_type_unified(arg, info);
4614 let actual_ty = actual_ut.as_ref().map(|ut| ut.to_rust_string());
4615 let expected_ty = expected_ut.to_rust_string();
4616 if matches!(&arg.kind, ExprKind::StringLit(_))
4620 && expected_ut.is_pointer()
4621 {
4622 syn_expr = crate::syn_codegen::method_call(syn_expr, "as_ptr", vec![]);
4623 }
4624 syn_expr = self.cast_arg_syn_if_needed(syn_expr, actual_ty.as_deref(), &expected_ty);
4625 }
4626 }
4627 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
4628 }
4629
4630 fn cast_arg_syn_if_needed(&self, arg_expr: syn::Expr,
4634 actual_ty: Option<&str>, expected_ty: &str) -> syn::Expr {
4635 use crate::syn_codegen::cast_syn_expr;
4636 if let Some(actual) = actual_ty {
4637 let actual_ut = UnifiedType::from_rust_str(actual);
4639 if self.is_rust_enum_type(&actual_ut) {
4640 if let Some(target) = normalize_integer_type(expected_ty) {
4641 return cast_syn_expr(arg_expr, target);
4642 }
4643 }
4644 let na = normalize_integer_type(actual);
4645 let ne = normalize_integer_type(expected_ty);
4646 if let (Some(a), Some(e)) = (na, ne) {
4647 if !integer_types_compatible(a, e) {
4648 return cast_syn_expr(arg_expr, e);
4649 }
4650 return arg_expr;
4651 }
4652 if actual != expected_ty {
4654 let actual_ut = UnifiedType::from_rust_str(actual);
4655 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4656 if actual_ut.is_pointer() && expected_ut.is_pointer()
4657 && is_sv_subtype_cast(&actual_ut, &expected_ut) {
4658 let cast_ty = if actual.contains("*const") {
4659 expected_ty.replace("*mut", "*const")
4660 } else {
4661 expected_ty.to_string()
4662 };
4663 return cast_syn_expr(arg_expr, &cast_ty);
4664 }
4665 if actual_ut.is_pointer() && expected_ut.is_pointer()
4671 && expected_ut.is_void_pointer()
4672 {
4673 return cast_syn_expr(arg_expr, expected_ty);
4674 }
4675 if pointer_inner_compatible(&actual_ut, &expected_ut) {
4681 let top_mut_to_const = !actual_ut.is_const_pointer()
4682 && expected_ut.is_const_pointer();
4683 let top_const_same = actual_ut.is_const_pointer()
4684 == expected_ut.is_const_pointer();
4685 let inner_exact_match = actual_ut.inner_type()
4687 .zip(expected_ut.inner_type())
4688 .is_some_and(|(a, b)| a.to_rust_string() == b.to_rust_string());
4689 let auto_coerces = (top_mut_to_const || top_const_same)
4690 && inner_exact_match;
4691 if !auto_coerces {
4692 return cast_syn_expr(arg_expr, expected_ty);
4693 }
4694 }
4695 }
4696 return arg_expr;
4697 }
4698 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4700 if expected_ut.is_pointer() {
4701 if let Some(inner) = expected_ut.inner_type() {
4702 if let UnifiedType::Named(name) = inner {
4703 let n = name.as_str();
4704 if matches!(n, "SV" | "GV" | "HV" | "AV" | "CV" | "IO") {
4705 if matches!(&arg_expr, syn::Expr::Call(_) | syn::Expr::MethodCall(_)) {
4706 return cast_syn_expr(arg_expr, expected_ty);
4707 }
4708 }
4709 }
4710 }
4711 }
4712 arg_expr
4713 }
4714
4715 fn try_build_common_macro_fn_call(
4731 &mut self,
4732 func: &Expr,
4733 args: &[Expr],
4734 info: Option<&MacroInferInfo>,
4735 ) -> Option<syn::Expr> {
4736 use crate::syn_codegen::*;
4737
4738 let member_id = match &func.kind {
4739 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => *member,
4740 _ => return None,
4741 };
4742
4743 let mut is_fn_ptr = self
4745 .fields_dict
4746 .and_then(|d| d.canonical_field(member_id).map(|(_, f)| f.is_fn_pointer))
4747 .unwrap_or(false);
4748
4749 if !is_fn_ptr {
4754 let field_name = self.interner.get(member_id);
4755 if let Some(ut) = self.field_type_map.get(field_name) {
4756 let ty_str = ut.to_rust_string();
4757 if type_str_is_fn_pointer(&ty_str) {
4758 is_fn_ptr = true;
4759 } else if let Some(dict) = self.rust_decl_dict {
4760 if let Some(alias) = dict.types.get(&ty_str) {
4761 if type_str_is_fn_pointer(&alias.ty) {
4762 is_fn_ptr = true;
4763 }
4764 }
4765 }
4766 }
4767 }
4768
4769 if !is_fn_ptr {
4770 return None;
4771 }
4772
4773 let field_access = self.build_syn_expr(func, info);
4775 let callee = method_call(field_access, "unwrap_unchecked", vec![]);
4777
4778 let mut punctuated = syn::punctuated::Punctuated::new();
4780 for (i, arg) in args.iter().enumerate() {
4781 let s = self.build_arg_string_unified(arg, info, None, i);
4782 let parsed = syn::parse_str(&s).unwrap_or_else(|_| int_lit(0));
4783 punctuated.push(parsed);
4784 }
4785
4786 Some(syn::Expr::Call(syn::ExprCall {
4787 attrs: vec![],
4788 func: Box::new(callee),
4789 paren_token: Default::default(),
4790 args: punctuated,
4791 }))
4792 }
4793
4794 fn build_lvalue_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
4796 if let ExprKind::MacroCall { expanded, .. } = &expr.kind {
4797 return self.build_syn_expr(expanded, info);
4798 }
4799 if let ExprKind::Call { func, args } = &expr.kind {
4800 if let Some(expanded) = self.try_expand_call_as_lvalue_syn(func, args, info) {
4801 return expanded;
4802 }
4803 let syn_expr = self.build_syn_expr(expr, info);
4804 let s = crate::syn_codegen::expr_to_string(&syn_expr);
4805 self.codegen_errors.push(format!("invalid lvalue: {} cannot be assigned to", s));
4806 return syn_expr;
4807 }
4808 self.build_syn_expr(expr, info)
4809 }
4810
4811 fn build_inc_dec_syn_expr(&mut self, inner: &Expr, info: Option<&MacroInferInfo>,
4814 is_inc: bool, is_post: bool) -> syn::Expr {
4815 use crate::syn_codegen::*;
4816 let lv = self.build_lvalue_syn_expr(inner, info);
4817 let is_ptr = self.is_pointer_expr_unified(inner, info)
4818 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer());
4819 let step_stmt: syn::Stmt = if is_ptr {
4821 let method = if is_inc { "wrapping_add" } else { "wrapping_sub" };
4823 let call = method_call(lv.clone(), method, vec![int_lit(1)]);
4824 semi_stmt(assign_expr(lv.clone(), call))
4825 } else {
4826 let op = if is_inc {
4827 syn::BinOp::AddAssign(Default::default())
4828 } else {
4829 syn::BinOp::SubAssign(Default::default())
4830 };
4831 semi_stmt(assign_op_expr(lv.clone(), op, int_lit(1)))
4832 };
4833 if is_post {
4834 let save = let_stmt("_t", lv.clone());
4836 block_with_value(vec![save, step_stmt], ident_expr("_t"))
4837 } else {
4838 block_with_value(vec![step_stmt], lv)
4840 }
4841 }
4842
4843 fn build_assign_syn_expr(&mut self, op: AssignOp, lhs: &Expr, rhs: &Expr,
4846 info: Option<&MacroInferInfo>) -> syn::Expr {
4847 use crate::syn_codegen::*;
4848 let l = self.build_lvalue_syn_expr(lhs, info);
4849 let lhs_ut = self.infer_expr_type_unified(lhs, info);
4850
4851 let r: syn::Expr = if is_null_literal(rhs) && op == AssignOp::Assign {
4853 match &lhs_ut {
4854 Some(lut) if lut.is_pointer() => {
4855 if lut.is_const_pointer() {
4856 syn::parse_str("std::ptr::null()").unwrap_or_else(|_| int_lit(0))
4857 } else {
4858 syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0))
4859 }
4860 }
4861 Some(_) => int_lit(0),
4862 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
4863 }
4864 } else {
4865 let mut r_expr = self.build_syn_expr(rhs, info);
4866 if op == AssignOp::Assign {
4868 if let Some(ref lut) = lhs_ut {
4870 if lut.is_float() {
4871 if let ExprKind::IntLit(n) = &rhs.kind {
4872 r_expr = syn::parse_str(&format!("{}.0", n))
4873 .unwrap_or_else(|_| int_lit(0));
4874 }
4875 }
4876 }
4877 if let Some(ref lut) = lhs_ut {
4878 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4879 let ls = lut.to_rust_string();
4880 let rs = rut.to_rust_string();
4881 if let (Some(nl), Some(nr)) = (
4882 normalize_integer_type(&ls),
4883 normalize_integer_type(&rs),
4884 ) {
4885 if !integer_types_compatible(nl, nr) {
4886 r_expr = cast_syn_expr(r_expr, nl);
4887 }
4888 }
4889 else if lut.is_pointer() && rut.is_pointer()
4891 && lut.is_const_pointer() != rut.is_const_pointer()
4892 {
4893 r_expr = cast_syn_expr(r_expr, &ls);
4894 }
4895 else if lut.is_pointer() && rut.is_pointer()
4897 && ls != rs
4898 && is_sv_subtype_cast(&rut, lut)
4899 {
4900 r_expr = cast_syn_expr(r_expr, &ls);
4901 }
4902 }
4903 }
4904 }
4905 r_expr
4906 };
4907
4908 if op == AssignOp::Assign {
4912 if let syn::Expr::MethodCall(mc) = &l {
4913 if mc.args.is_empty() {
4914 let method_name = mc.method.to_string();
4915 if self.is_bitfield_method(&method_name) {
4916 let setter_name = format!("set_{}", method_name);
4917 let arg_val = if let Some(dict) = self.rust_decl_dict {
4921 let ret_ty = dict.bitfield_method_types.iter()
4924 .find(|((_, m), _)| m == &method_name)
4925 .map(|(_, ty)| ty.clone());
4926 if let Some(ty) = ret_ty {
4927 cast_syn_expr(r, &ty)
4928 } else {
4929 r
4930 }
4931 } else {
4932 r
4933 };
4934 let setter_call = method_call(
4935 (*mc.receiver).clone(),
4936 &setter_name,
4937 vec![arg_val],
4938 );
4939 let stmt = semi_stmt(setter_call);
4940 return block_with_value(vec![stmt], l);
4941 }
4942 }
4943 }
4944 }
4945
4946 let stmt: syn::Stmt = match op {
4948 AssignOp::Assign => semi_stmt(assign_expr(l.clone(), r)),
4949 AssignOp::AddAssign | AssignOp::SubAssign => {
4950 let is_ptr = self.is_pointer_expr_unified(lhs, info)
4951 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer());
4952 if is_ptr {
4953 let method = if op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
4955 let r_usize = cast_syn_expr(r, "usize");
4956 let call = method_call(l.clone(), method, vec![r_usize]);
4957 semi_stmt(assign_expr(l.clone(), call))
4958 } else {
4959 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4960 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
4961 }
4962 }
4963 AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign => {
4964 let lt = &lhs_ut;
4968 let rt = self.infer_expr_type_unified(rhs, info);
4969 let r_final = {
4970 let mut casted = false;
4971 let mut ret = r;
4972 if let (Some(lut), Some(rut)) = (lt, &rt) {
4973 let ls = lut.to_rust_string();
4974 let rs = rut.to_rust_string();
4975 let nl = normalize_integer_type(&ls);
4976 let nr = normalize_integer_type(&rs);
4977 if nl.is_some() && nr.is_some() && nl != nr {
4978 ret = cast_syn_expr(ret, nl.unwrap());
4979 casted = true;
4980 }
4981 if !casted && self.is_rust_enum_type(rut) && nl.is_some() {
4983 ret = cast_syn_expr(ret, nl.unwrap());
4984 casted = true;
4985 }
4986 }
4987 if !casted {
4988 if let (Some(lut), None) = (lt, &rt) {
4989 let ls = lut.to_rust_string();
4990 if let Some(nl) = normalize_integer_type(&ls) {
4991 ret = cast_syn_expr(ret, nl);
4992 }
4993 }
4994 }
4995 ret
4996 };
4997 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4998 semi_stmt(assign_op_expr(l.clone(), syn_op, r_final))
4999 }
5000 _ => {
5001 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
5002 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
5003 }
5004 };
5005 block_with_value(vec![stmt], l)
5006 }
5007
5008 fn build_lvalue_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
5010 let syn_expr = self.build_lvalue_syn_expr(expr, info);
5011 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
5012 }
5013
5014 fn build_syn_expr_with_type_hint(&mut self, expr: &Expr, info: Option<&MacroInferInfo>,
5016 type_hint: Option<&str>) -> syn::Expr {
5017 use crate::syn_codegen::*;
5018 if let Some(ty) = type_hint {
5019 let ut = UnifiedType::from_rust_str(ty);
5020 if ut.is_pointer() && is_null_literal(expr) {
5021 return syn::parse_str(&null_ptr_expr(&ut)).unwrap_or_else(|_| int_lit(0));
5022 }
5023 if ut.is_bool() {
5024 match &expr.kind {
5025 ExprKind::IntLit(0) => return syn::parse_str("false").unwrap(),
5026 ExprKind::IntLit(1) => return syn::parse_str("true").unwrap(),
5027 _ => {}
5028 }
5029 }
5030 }
5031 self.build_syn_expr(expr, info)
5032 }
5033
5034 fn build_return_stmt(&mut self, expr: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
5044 use crate::syn_codegen::*;
5045 if let Some(ref rt) = self.current_return_type {
5046 if rt.is_pointer() && is_null_literal(expr) {
5047 return format!("{}return {};", indent, null_ptr_expr(rt));
5048 }
5049 if rt.is_bool() {
5050 match &expr.kind {
5051 ExprKind::IntLit(0) => return format!("{}return false;", indent),
5052 ExprKind::IntLit(1) => return format!("{}return true;", indent),
5053 _ => {
5054 let mut syn_expr = self.build_syn_expr(expr, info);
5055 if !self.is_bool_expr_with_dict(expr) && !is_bool_syn_expr(&syn_expr) {
5056 syn_expr = wrap_as_bool(syn_expr);
5057 }
5058 let s = normalize_parens(&expr_to_string(&syn_expr));
5059 return format!("{}return {};", indent, s);
5060 }
5061 }
5062 }
5063 }
5064 let mut syn_expr = self.build_syn_expr(expr, info);
5065 syn_expr = self.cast_return_syn_expr_if_needed(expr, info, syn_expr);
5066 let s = normalize_parens(&expr_to_string(&syn_expr));
5067 format!("{}return {};", indent, s)
5068 }
5069
5070 fn cast_return_syn_expr_if_needed(&self, expr: &Expr, info: Option<&MacroInferInfo>,
5073 syn_expr: syn::Expr) -> syn::Expr {
5074 let Some(ret_ut) = &self.current_return_type else { return syn_expr };
5075 let Some(expr_ut) = self.infer_expr_type_unified(expr, info) else { return syn_expr };
5076 let ret_s = ret_ut.to_rust_string();
5077 let expr_s = expr_ut.to_rust_string();
5078 if self.is_rust_enum_type(&expr_ut) {
5080 if let Some(nr) = normalize_integer_type(&ret_s) {
5081 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
5082 }
5083 }
5084 if let (Some(nr), Some(ne)) = (normalize_integer_type(&ret_s), normalize_integer_type(&expr_s)) {
5085 if !integer_types_compatible(nr, ne) {
5086 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
5087 }
5088 }
5089 if ret_ut.is_pointer() && expr_ut.is_pointer() && ret_s != expr_s
5093 && pointer_inner_compatible(ret_ut, &expr_ut)
5094 {
5095 return crate::syn_codegen::cast_syn_expr(syn_expr, &ret_s);
5096 }
5097 syn_expr
5098 }
5099
5100 fn build_assign_stmt(&mut self, op: &AssignOp, lhs: &Expr, rhs: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
5106 use crate::syn_codegen::*;
5107 let l = self.build_lvalue_string(lhs, info);
5108 let lhs_ut = self.infer_expr_type_unified(lhs, info);
5109
5110 let r_syn: syn::Expr = if is_null_literal(rhs) && *op == AssignOp::Assign {
5112 match &lhs_ut {
5113 Some(lut) if lut.is_pointer() => {
5114 let s = if lut.is_const_pointer() { "std::ptr::null()" } else { "std::ptr::null_mut()" };
5115 syn::parse_str(s).unwrap_or_else(|_| int_lit(0))
5116 }
5117 Some(_) => int_lit(0),
5118 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
5119 }
5120 } else {
5121 let mut r_syn = self.build_syn_expr(rhs, info);
5122 if *op == AssignOp::Assign {
5124 if let Some(ref lut) = lhs_ut {
5126 if lut.is_float() {
5127 if let ExprKind::IntLit(n) = &rhs.kind {
5128 r_syn = syn::parse_str(&format!("{}.0", n))
5129 .unwrap_or_else(|_| int_lit(0));
5130 }
5131 }
5132 }
5133 if let Some(ref lut) = lhs_ut {
5134 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
5135 let ls = lut.to_rust_string();
5136 let rs = rut.to_rust_string();
5137 if self.is_rust_enum_type(&rut) {
5139 if let Some(nl) = normalize_integer_type(&ls) {
5140 r_syn = cast_syn_expr(r_syn, nl);
5141 }
5142 } else if let (Some(nl), Some(nr)) = (normalize_integer_type(&ls), normalize_integer_type(&rs)) {
5143 if nl != nr {
5146 r_syn = cast_syn_expr(r_syn, nl);
5147 }
5148 }
5149 if pointer_const_differs(lut, &rut) {
5152 r_syn = cast_syn_expr(r_syn, &ls);
5153 } else if lut.is_pointer() && rut.is_pointer()
5154 && ls != rs
5155 && pointer_inner_compatible(lut, &rut)
5156 {
5157 r_syn = cast_syn_expr(r_syn, &ls);
5158 }
5159 else if lut.is_pointer() && rut.is_pointer()
5162 && ls != rs
5163 && is_sv_subtype_cast(&rut, lut)
5164 {
5165 r_syn = cast_syn_expr(r_syn, &ls);
5166 }
5167 }
5168 }
5169 } else if matches!(op, AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign) {
5170 let rt = self.infer_expr_type_unified(rhs, info);
5171 if let (Some(lut), Some(rut)) = (&lhs_ut, &rt) {
5172 let ls = lut.to_rust_string();
5173 let rs = rut.to_rust_string();
5174 let nl = normalize_integer_type(&ls);
5175 let nr = normalize_integer_type(&rs);
5176 if nl.is_some() && nr.is_some() && nl != nr {
5177 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5178 } else if self.is_rust_enum_type(rut) && nl.is_some() {
5179 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5181 }
5182 } else if let (Some(lut), None) = (&lhs_ut, &rt) {
5183 let ls = lut.to_rust_string();
5184 if let Some(nl) = normalize_integer_type(&ls) {
5185 r_syn = cast_syn_expr(r_syn, nl);
5186 }
5187 }
5188 }
5189 r_syn
5190 };
5191
5192 match op {
5193 AssignOp::Assign => {
5194 let r = normalize_parens(&expr_to_string(&r_syn));
5195 format!("{}{} = {};", indent, l, r)
5196 }
5197 AssignOp::AddAssign | AssignOp::SubAssign => {
5198 if self.is_pointer_expr_unified(lhs, info)
5199 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer()) {
5200 let method = if *op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
5201 let r_usize = cast_syn_expr(r_syn, "usize");
5202 let r = expr_to_string(&r_usize);
5203 format!("{}{} = {}.{}({});", indent, l, l, method, r)
5204 } else {
5205 let r = normalize_parens(&expr_to_string(&r_syn));
5206 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5207 }
5208 }
5209 _ => {
5210 let r = normalize_parens(&expr_to_string(&r_syn));
5211 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5212 }
5213 }
5214 }
5215
5216 fn build_expr_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
5218 let syn_expr = self.build_syn_expr(expr, info);
5219 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
5220 }
5221
5222 fn stmt_to_rust(&mut self, stmt: &Stmt, info: &MacroInferInfo) -> String {
5224 match stmt {
5225 Stmt::Expr(Some(expr), _) => {
5226 format!("{};", self.build_expr_string(expr, Some(info)))
5227 }
5228 Stmt::Expr(None, _) => ";".to_string(),
5229 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, "", Some(info)),
5230 Stmt::Return(None, _) => "return;".to_string(),
5231 _ => self.todo_marker("stmt")
5232 }
5233 }
5234
5235 fn type_name_to_rust(&mut self, type_name: &crate::ast::TypeName) -> String {
5237 let base_type = self.decl_specs_to_rust(&type_name.specs);
5239
5240 let mut result = if let Some(ref decl) = type_name.declarator {
5242 self.apply_derived_to_type(&base_type, &decl.derived)
5243 } else {
5244 base_type
5245 };
5246
5247 if type_name.specs.qualifiers.is_const {
5250 if let Some(pos) = result.rfind("*mut ") {
5251 result.replace_range(pos..pos + 5, "*const ");
5252 }
5253 }
5254
5255 result
5256 }
5257
5258 fn decl_specs_to_rust(&mut self, specs: &DeclSpecs) -> String {
5260 for spec in &specs.type_specs {
5262 if let TypeSpec::TypedefName(name) = spec {
5263 if let Some(generic_name) = self.current_type_param_map.get(name) {
5265 return generic_name.clone();
5266 }
5267 let name_str = self.interner.get(*name).to_string();
5268 if !self.known_symbols.contains(&name_str) {
5270 self.codegen_errors.push(format!("undefined type: {}", name_str));
5271 }
5272 return name_str;
5273 }
5274 }
5275
5276 let mut is_void = false;
5278 let mut is_char = false;
5279 let mut is_int = false;
5280 let mut is_short = false;
5281 let mut is_long = 0usize;
5282 let mut is_unsigned = false;
5283 let mut is_float = false;
5284 let mut is_double = false;
5285
5286 for spec in &specs.type_specs {
5287 match spec {
5288 TypeSpec::Void => is_void = true,
5289 TypeSpec::Char => is_char = true,
5290 TypeSpec::Int => is_int = true,
5291 TypeSpec::Short => is_short = true,
5292 TypeSpec::Long => is_long += 1,
5293 TypeSpec::Unsigned => is_unsigned = true,
5294 TypeSpec::Signed => {}
5295 TypeSpec::Float => is_float = true,
5296 TypeSpec::Double => is_double = true,
5297 TypeSpec::Bool => return "bool".to_string(),
5298 TypeSpec::Struct(spec) => {
5299 if let Some(n) = spec.name {
5300 return self.interner.get(n).to_string();
5301 } else {
5302 return self.type_marker().to_string();
5303 }
5304 }
5305 TypeSpec::Union(spec) => {
5306 if let Some(n) = spec.name {
5307 return self.interner.get(n).to_string();
5308 } else {
5309 return self.type_marker().to_string();
5310 }
5311 }
5312 TypeSpec::Enum(spec) => {
5313 if let Some(n) = spec.name {
5314 return self.interner.get(n).to_string();
5315 } else {
5316 return "c_int".to_string();
5317 }
5318 }
5319 _ => {}
5320 }
5321 }
5322
5323 if is_void {
5324 return "()".to_string();
5325 }
5326
5327 if is_float {
5328 return "c_float".to_string();
5329 }
5330
5331 if is_double {
5332 return if is_long > 0 { "c_longdouble".to_string() } else { "c_double".to_string() };
5333 }
5334
5335 if is_char {
5336 return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() };
5337 }
5338
5339 if is_short {
5340 return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() };
5341 }
5342
5343 if is_long >= 2 {
5344 return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() };
5345 }
5346
5347 if is_long == 1 {
5348 return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() };
5349 }
5350
5351 if is_int || is_unsigned {
5352 return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() };
5353 }
5354
5355 self.type_marker().to_string()
5356 }
5357
5358 fn apply_derived_to_type(&mut self, base: &str, derived: &[DerivedDecl]) -> String {
5360 let fn_idx = derived
5362 .iter()
5363 .position(|d| matches!(d, DerivedDecl::Function(_)));
5364
5365 if let Some(idx) = fn_idx {
5366 if let DerivedDecl::Function(param_list) = &derived[idx] {
5367 let is_fn_pointer =
5369 idx > 0 && matches!(derived[idx - 1], DerivedDecl::Pointer(_));
5370
5371 let return_end = if is_fn_pointer { idx - 1 } else { idx };
5373 let return_derived = &derived[..return_end];
5374 let return_type = self.apply_simple_derived(base, return_derived);
5375
5376 let params: Vec<_> = param_list
5378 .params
5379 .iter()
5380 .map(|p| self.param_type_only(p))
5381 .collect();
5382 let params_str = params.join(", ");
5383
5384 let fn_type =
5386 format!("unsafe extern \"C\" fn({}) -> {}", params_str, return_type);
5387
5388 if is_fn_pointer {
5390 return format!("Option<{}>", fn_type);
5391 }
5392 return fn_type;
5393 }
5394 }
5395
5396 self.apply_simple_derived(base, derived)
5398 }
5399
5400 fn apply_simple_derived(&self, base: &str, derived: &[DerivedDecl]) -> String {
5402 self.apply_simple_derived_with_specs_const(base, derived, false)
5403 }
5404
5405 fn apply_simple_derived_with_specs_const(&self, base: &str, derived: &[DerivedDecl], specs_is_const: bool) -> String {
5407 let mut result = base.to_string();
5408 let mut is_first_pointer = true;
5409 for d in derived.iter().rev() {
5410 match d {
5411 DerivedDecl::Pointer(quals) => {
5412 if result == "()" {
5414 result = "c_void".to_string();
5415 }
5416 let pointee_const = if is_first_pointer {
5420 specs_is_const
5421 } else {
5422 quals.is_const
5423 };
5424 if pointee_const {
5425 result = format!("*const {}", result);
5426 } else {
5427 result = format!("*mut {}", result);
5428 }
5429 is_first_pointer = false;
5430 }
5431 DerivedDecl::Array(arr) => {
5432 if result == "()" {
5434 result = "c_void".to_string();
5435 }
5436 if let Some(ref size_expr) = arr.size {
5437 if let ExprKind::IntLit(n) = &size_expr.kind {
5439 result = format!("[{}; {}]", result, n);
5440 } else {
5441 result = format!("*mut {}", result);
5442 }
5443 } else {
5444 result = format!("*mut {}", result);
5445 }
5446 }
5447 DerivedDecl::Function(_) => {
5448 }
5450 }
5451 }
5452 result
5453 }
5454
5455 fn param_type_only(&mut self, param: &ParamDecl) -> String {
5457 let ty = self.decl_specs_to_rust(¶m.specs);
5458 if let Some(ref declarator) = param.declarator {
5459 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5463 } else {
5464 ty
5465 }
5466 }
5467
5468 pub fn generate_inline_fn(mut self, name: crate::InternedStr, func_def: &FunctionDef) -> GeneratedCode {
5470 let name_str = self.interner.get(name);
5471
5472 let mut_params = {
5474 let mut all_names = HashSet::new();
5475 for d in &func_def.declarator.derived {
5477 if let DerivedDecl::Function(param_list) = d {
5478 for p in ¶m_list.params {
5479 if let Some(ref declarator) = p.declarator {
5480 if let Some(param_name) = declarator.name {
5481 all_names.insert(param_name);
5482 }
5483 }
5484 }
5485 }
5486 }
5487 for item in &func_def.body.items {
5489 if let BlockItem::Decl(decl) = item {
5490 for init_decl in &decl.declarators {
5491 if let Some(var_name) = init_decl.declarator.name {
5492 all_names.insert(var_name);
5493 }
5494 }
5495 }
5496 }
5497 let mut result = HashSet::new();
5498 for item in &func_def.body.items {
5499 if let BlockItem::Stmt(stmt) = item {
5500 collect_mut_params_from_stmt(stmt, &all_names, &mut result);
5501 }
5502 }
5503 result
5504 };
5505
5506 self.mut_local_names = mut_params.clone();
5508
5509 let params_str = self.build_fn_param_list(&func_def.declarator.derived, &mut_params);
5511
5512 let return_type = self.decl_specs_to_rust(&func_def.specs);
5514
5515 let return_derived: Vec<_> = func_def.declarator.derived.iter()
5519 .filter(|d| !matches!(d, DerivedDecl::Function(_)))
5520 .cloned()
5521 .collect();
5522 let return_type = self.apply_simple_derived_with_specs_const(&return_type, &return_derived, func_def.specs.qualifiers.is_const);
5523 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
5524
5525 for d in &func_def.declarator.derived {
5527 if let DerivedDecl::Function(param_list) = d {
5528 for p in ¶m_list.params {
5529 if let Some(ref declarator) = p.declarator {
5530 if let Some(param_name) = declarator.name {
5531 let ty = self.param_type_only(p);
5532 self.current_param_types.insert(param_name, UnifiedType::from_rust_str(&ty));
5533 self.current_local_names.insert(param_name);
5534 }
5535 }
5536 }
5537 }
5538 }
5539
5540 self.collect_local_names_recursive(&func_def.body);
5543
5544 let is_thx_dependent = self.perl_threaded
5546 && self.is_inline_fn_thx_dependent(&func_def.declarator.derived);
5547 let thx_info = if is_thx_dependent { " [THX]" } else { "" };
5548
5549 self.dump_ast_comment_for_body(name_str, &func_def.body);
5551
5552 self.writeln(&format!("/// {}{} - inline function", name_str, thx_info));
5554 self.writeln("#[inline]");
5555 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
5556
5557 self.writeln(&format!("pub unsafe fn {}({}) -> {} {{", name_str, params_str, return_type));
5559
5560 let needs_unsafe = func_def.function_call_count > 0 || func_def.deref_count > 0;
5562
5563 if needs_unsafe {
5564 self.writeln(" unsafe {");
5565 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5566 self.buffer.push_str(&body_str);
5567 self.writeln(" }");
5568 } else {
5569 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5570 self.buffer.push_str(&body_str);
5571 }
5572
5573 self.writeln("}");
5574 self.writeln("");
5575
5576 self.into_generated_code()
5577 }
5578
5579 fn build_fn_param_list(&mut self, derived: &[DerivedDecl], mut_params: &HashSet<InternedStr>) -> String {
5581 for d in derived {
5582 if let DerivedDecl::Function(param_list) = d {
5583 if is_void_only_param_list(¶m_list.params) {
5587 return String::new();
5588 }
5589 let params: Vec<_> = param_list.params.iter()
5590 .map(|p| self.param_decl_to_rust(p, mut_params))
5591 .collect();
5592 let mut result = params.join(", ");
5593 if param_list.is_variadic {
5594 if !result.is_empty() {
5595 result.push_str(", ");
5596 }
5597 result.push_str("...");
5598 }
5599 return result;
5600 }
5601 }
5602 String::new()
5603 }
5604
5605 fn is_inline_fn_thx_dependent(&self, derived: &[DerivedDecl]) -> bool {
5609 for d in derived {
5610 if let DerivedDecl::Function(param_list) = d {
5611 if let Some(first_param) = param_list.params.first() {
5612 if let Some(ref declarator) = first_param.declarator {
5613 if let Some(name) = declarator.name {
5614 let name_str = self.interner.get(name);
5615 return name_str == "my_perl";
5616 }
5617 }
5618 }
5619 return false;
5620 }
5621 }
5622 false
5623 }
5624
5625 fn param_decl_to_rust(&mut self, param: &ParamDecl, mut_params: &HashSet<InternedStr>) -> String {
5627 let param_name_interned = param.declarator
5628 .as_ref()
5629 .and_then(|d| d.name);
5630 let name = param_name_interned
5631 .map(|n| escape_rust_keyword(self.interner.get(n)))
5632 .unwrap_or_else(|| "_".to_string());
5633
5634 let ty = self.decl_specs_to_rust(¶m.specs);
5635
5636 let ty = if let Some(ref declarator) = param.declarator {
5638 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5639 } else {
5640 ty
5641 };
5642
5643 if let Some(n) = param_name_interned {
5645 self.current_param_types.insert(n, UnifiedType::from_rust_str(&ty));
5646 }
5647
5648 let mut_prefix = if param_name_interned.is_some_and(|n| mut_params.contains(&n)) {
5649 "mut "
5650 } else {
5651 ""
5652 };
5653
5654 format!("{}{}: {}", mut_prefix, name, ty)
5655 }
5656
5657 fn decl_to_rust_let(&mut self, decl: &Declaration, indent: &str) -> String {
5659 let mut result = String::new();
5660
5661 let base_type = self.decl_specs_to_rust(&decl.specs);
5663
5664 for init_decl in &decl.declarators {
5666 let name = init_decl.declarator.name
5667 .map(|n| escape_rust_keyword(self.interner.get(n)))
5668 .unwrap_or_else(|| "_".to_string());
5669
5670 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
5672
5673 if let Some(ref init) = init_decl.init {
5675 match init {
5676 Initializer::Expr(expr) => {
5677 let mut init_syn = self.build_syn_expr(expr, None);
5682 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5683 let decl_s = ty.clone();
5684 let expr_s = expr_ut.to_rust_string();
5685 let nd = normalize_integer_type(&decl_s);
5686 let ne = normalize_integer_type(&expr_s);
5687 if let (Some(d), Some(e)) = (nd, ne) {
5688 if !integer_types_compatible(d, e) {
5689 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, d);
5690 }
5691 }
5692 }
5693 let decl_is_mut_ptr = ty.contains("*mut ") && !ty.contains("*const ");
5698 let decl_is_const_ptr = ty.contains("*const ") && !ty.contains("*mut ");
5699 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5700 if expr_ut.is_pointer() {
5701 if decl_is_mut_ptr && expr_ut.is_const_pointer() {
5702 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5703 } else if decl_is_const_ptr && !expr_ut.is_const_pointer() {
5704 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5705 }
5706 }
5707 }
5708 let init_expr = normalize_parens(&crate::syn_codegen::expr_to_string(&init_syn));
5709 let init_expr = if is_null_literal(expr) && ty.contains("*mut") {
5711 "std::ptr::null_mut()".to_string()
5712 } else if is_null_literal(expr) && ty.contains("*const") {
5713 "std::ptr::null()".to_string()
5714 } else {
5715 init_expr
5716 };
5717 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5718 result.push_str(&format!("{}let {}{}: {} = {};\n", indent, mut_kw, name, ty, strip_outer_parens(&init_expr)));
5719 }
5720 Initializer::List(_) => {
5721 result.push_str(&format!("{}let {}: {} = /* init list */;\n", indent, name, ty));
5723 }
5724 }
5725 } else {
5726 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5728 result.push_str(&format!("{}let {}{}: {}; // uninitialized\n", indent, mut_kw, name, ty));
5729 }
5730 }
5731
5732 result
5733 }
5734
5735 fn compound_stmt_to_string(&mut self, stmt: &CompoundStmt, indent: &str) -> String {
5737 let mut result = String::new();
5738 for item in &stmt.items {
5739 match item {
5740 BlockItem::Decl(decl) => {
5741 self.collect_decl_types(decl);
5742 result.push_str(&self.decl_to_rust_let(decl, indent));
5743 }
5744 BlockItem::Stmt(s) => {
5745 let rust_stmt = self.stmt_to_rust_inline(s, indent);
5746 result.push_str(&rust_stmt);
5747 result.push('\n');
5748 }
5749 }
5750 }
5751 result
5752 }
5753
5754 fn stmt_to_rust_inline(&mut self, stmt: &Stmt, indent: &str) -> String {
5756 match stmt {
5757 Stmt::Expr(Some(expr), _) => {
5758 if let ExprKind::Assign { op, lhs, rhs } = &expr.kind {
5760 self.build_assign_stmt(op, lhs, rhs, indent, None)
5761 } else {
5762 format!("{}{};", indent, self.build_expr_string(expr, None))
5763 }
5764 }
5765 Stmt::Expr(None, _) => String::new(),
5766 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, indent, None),
5767 Stmt::Return(None, _) => format!("{}return;", indent),
5768 Stmt::If { cond, then_stmt, else_stmt, .. } => {
5769 let cond_str = self.build_expr_string(cond, None);
5770 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5772 let mut result = format!("{}if {} {{\n", indent, normalize_parens(&cond_bool));
5773 let nested_indent = format!("{} ", indent);
5774 result.push_str(&self.stmt_to_rust_inline(then_stmt, &nested_indent));
5775 result.push_str("\n");
5776 result.push_str(&format!("{}}}", indent));
5777 if let Some(else_stmt) = else_stmt {
5778 result.push_str(" else {\n");
5779 result.push_str(&self.stmt_to_rust_inline(else_stmt, &nested_indent));
5780 result.push_str("\n");
5781 result.push_str(&format!("{}}}", indent));
5782 }
5783 result
5784 }
5785 Stmt::Compound(compound) => {
5786 let mut result = format!("{}{{\n", indent);
5787 for item in &compound.items {
5788 match item {
5789 BlockItem::Stmt(s) => {
5790 let nested_indent = format!("{} ", indent);
5791 result.push_str(&self.stmt_to_rust_inline(s, &nested_indent));
5792 result.push_str("\n");
5793 }
5794 BlockItem::Decl(decl) => {
5795 self.collect_decl_types(decl);
5796 let nested_indent = format!("{} ", indent);
5797 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5798 }
5799 }
5800 }
5801 result.push_str(&format!("{}}}", indent));
5802 result
5803 }
5804 Stmt::While { cond, body, .. } => {
5805 let cond_str = self.build_expr_string(cond, None);
5806 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5808 let mut result = format!("{}while {} {{\n", indent, cond_bool);
5809 let nested_indent = format!("{} ", indent);
5810 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5811 result.push_str("\n");
5812 result.push_str(&format!("{}}}", indent));
5813 result
5814 }
5815 Stmt::For { init, cond, step, body, .. } => {
5816 let mut result = format!("{}{{\n", indent);
5817 let nested_indent = format!("{} ", indent);
5818
5819 if let Some(for_init) = init {
5821 match for_init {
5822 ForInit::Expr(expr) => {
5823 result.push_str(&format!("{}{};\n", nested_indent, self.build_expr_string(expr, None)));
5824 }
5825 ForInit::Decl(decl) => {
5826 self.collect_decl_types(decl);
5827 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5828 }
5829 }
5830 }
5831
5832 if let Some(cond_expr) = cond {
5834 let cond_str = self.build_expr_string(cond_expr, None);
5835 let cond_bool = self.wrap_as_bool_condition_inline(cond_expr, &cond_str);
5837 result.push_str(&format!("{}while {} {{\n", nested_indent, cond_bool));
5838 } else {
5839 result.push_str(&format!("{}loop {{\n", nested_indent));
5840 }
5841
5842 let body_indent = format!("{} ", nested_indent);
5843
5844 result.push_str(&self.stmt_to_rust_inline(body, &body_indent));
5846 result.push_str("\n");
5847
5848 if let Some(step_expr) = step {
5850 result.push_str(&format!("{}{};\n", body_indent, self.build_expr_string(step_expr, None)));
5851 }
5852
5853 result.push_str(&format!("{}}}\n", nested_indent));
5854 result.push_str(&format!("{}}}", indent));
5855 result
5856 }
5857 Stmt::DoWhile { body, cond, .. } => {
5858 if is_zero_constant(cond) {
5861 if !stmt_contains_top_level_break(body) {
5866 let mut result = format!("{}{{\n", indent);
5867 let nested_indent = format!("{} ", indent);
5868 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5869 result.push_str("\n");
5870 result.push_str(&format!("{}}}", indent));
5871 return result;
5872 }
5873 let mut result = format!("{}loop {{\n", indent);
5874 let nested_indent = format!("{} ", indent);
5875 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5876 result.push_str("\n");
5877 result.push_str(&format!("{} break;\n", indent));
5878 result.push_str(&format!("{}}}", indent));
5879 return result;
5880 }
5881
5882 let mut result = format!("{}loop {{\n", indent);
5884 let nested_indent = format!("{} ", indent);
5885 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5886 result.push_str("\n");
5887 let cond_str = self.build_expr_string(cond, None);
5888 let break_cond = if is_boolean_expr(cond) {
5892 normalize_parens(&format!("!({})", cond_str))
5893 } else {
5894 format!("{} == 0", cond_str)
5895 };
5896 result.push_str(&format!("{} if {} {{ break; }}\n", indent, break_cond));
5897 result.push_str(&format!("{}}}", indent));
5898 result
5899 }
5900 Stmt::Switch { expr, body, .. } => {
5901 let expr_str = self.build_expr_string(expr, None);
5902 let mut result = format!("{}match {} {{\n", indent, expr_str);
5903 let nested_indent = format!("{} ", indent);
5904
5905 self.collect_switch_cases(body, &nested_indent, &mut result);
5907
5908 result.push_str(&format!("{}}}", indent));
5909 result
5910 }
5911 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5912 let case_val = self.build_expr_string(case_expr, None);
5914 let mut result = format!("{}{} => {{\n", indent, case_val);
5915 let body_indent = format!("{} ", indent);
5916 result.push_str(&self.stmt_to_rust_inline(case_stmt, &body_indent));
5917 result.push_str("\n");
5918 result.push_str(&format!("{}}}", indent));
5919 result
5920 }
5921 Stmt::Default { stmt: default_stmt, .. } => {
5922 let mut result = format!("{}_ => {{\n", indent);
5923 let body_indent = format!("{} ", indent);
5924 result.push_str(&self.stmt_to_rust_inline(default_stmt, &body_indent));
5925 result.push_str("\n");
5926 result.push_str(&format!("{}}}", indent));
5927 result
5928 }
5929 Stmt::Goto(label, _) => {
5930 let label_str = self.interner.get(*label);
5931 format!("{}break '{}; // goto", indent, label_str)
5932 }
5933 Stmt::Label { name, stmt: label_stmt, .. } => {
5934 let label_str = self.interner.get(*name);
5935 let mut result = format!("{}'{}: {{\n", indent, label_str);
5936 let nested_indent = format!("{} ", indent);
5937 result.push_str(&self.stmt_to_rust_inline(label_stmt, &nested_indent));
5938 result.push_str("\n");
5939 result.push_str(&format!("{}}}", indent));
5940 result
5941 }
5942 Stmt::Break(_) => format!("{}break;", indent),
5943 Stmt::Continue(_) => format!("{}continue;", indent),
5944 _ => self.todo_marker(&format!("{:?}", std::mem::discriminant(stmt)))
5945 }
5946 }
5947
5948 fn collect_switch_cases(&mut self, stmt: &Stmt, indent: &str, result: &mut String) {
5950 struct SwitchCase {
5952 patterns: Vec<String>, body_stmts: Vec<String>,
5954 is_default: bool,
5955 }
5956
5957 let mut cases: Vec<SwitchCase> = Vec::new();
5958 let body_indent = format!("{} ", indent);
5959
5960 fn collect_items<'a>(stmt: &'a Stmt, items: &mut Vec<&'a BlockItem>) {
5962 if let Stmt::Compound(compound) = stmt {
5963 for item in &compound.items {
5964 items.push(item);
5965 }
5966 }
5967 }
5968
5969 fn flatten_case_chain<'a>(stmt: &'a Stmt, patterns: &mut Vec<&'a Expr>) -> (&'a Stmt, bool) {
5971 match stmt {
5972 Stmt::Case { expr, stmt: inner_stmt, .. } => {
5973 patterns.push(expr);
5974 flatten_case_chain(inner_stmt, patterns)
5975 }
5976 Stmt::Default { stmt: inner_stmt, .. } => {
5977 (inner_stmt, true)
5979 }
5980 other => (other, false)
5981 }
5982 }
5983
5984 let mut items: Vec<&BlockItem> = Vec::new();
5985 collect_items(stmt, &mut items);
5986
5987 for item in items {
5988 match item {
5989 BlockItem::Stmt(s) => {
5990 match s {
5991 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5992 let mut patterns: Vec<&Expr> = vec![case_expr];
5994 let (final_stmt, has_default) = flatten_case_chain(case_stmt, &mut patterns);
5995
5996 let pattern_strs: Vec<String> = patterns.iter()
5998 .map(|e| self.expr_to_rust_pattern(e))
5999 .collect();
6000
6001 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
6003 vec![]
6004 } else {
6005 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
6006 };
6007 cases.push(SwitchCase {
6008 patterns: pattern_strs,
6009 body_stmts,
6010 is_default: has_default,
6011 });
6012 }
6013 Stmt::Default { stmt: default_stmt, .. } => {
6014 let mut patterns: Vec<&Expr> = Vec::new();
6016 let (final_stmt, _) = flatten_case_chain(default_stmt, &mut patterns);
6017
6018 let pattern_strs: Vec<String> = patterns.iter()
6020 .map(|e| self.expr_to_rust_pattern(e))
6021 .collect();
6022
6023 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
6025 vec![]
6026 } else {
6027 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
6028 };
6029 cases.push(SwitchCase {
6030 patterns: pattern_strs,
6031 body_stmts,
6032 is_default: true,
6033 });
6034 }
6035 Stmt::Break(_) => {
6036 }
6039 other => {
6040 if let Some(last) = cases.last_mut() {
6042 last.body_stmts.push(self.stmt_to_rust_inline(other, &body_indent));
6043 }
6044 }
6046 }
6047 }
6048 BlockItem::Decl(decl) => {
6049 self.collect_decl_types(decl);
6050 if let Some(last) = cases.last_mut() {
6052 last.body_stmts.push(self.decl_to_rust_let(decl, &body_indent));
6053 }
6054 }
6055 }
6056 }
6057
6058 let has_default = cases.iter().any(|c| c.is_default);
6060 for case in &cases {
6061 let pattern = if case.is_default {
6062 if case.patterns.is_empty() {
6063 "_".to_string()
6064 } else {
6065 format!("{} | _", case.patterns.join(" | "))
6067 }
6068 } else {
6069 case.patterns.join(" | ")
6070 };
6071
6072 result.push_str(&format!("{}{} => {{\n", indent, pattern));
6073 for stmt in &case.body_stmts {
6074 result.push_str(stmt);
6075 result.push_str("\n");
6076 }
6077 result.push_str(&format!("{}}}\n", indent));
6078 }
6079 if !has_default {
6083 result.push_str(&format!("{}_ => {{}}\n", indent));
6084 }
6085 }
6086
6087 fn expr_to_field_path(&self, expr: &Expr) -> Option<String> {
6091 match &expr.kind {
6092 ExprKind::Ident(name) => {
6093 Some(self.interner.get(*name).to_string())
6094 }
6095 ExprKind::Member { expr: base, member } => {
6096 let base_path = self.expr_to_field_path(base)?;
6097 let member_name = self.interner.get(*member);
6098 Some(format!("{}.{}", base_path, member_name))
6099 }
6100 _ => None,
6101 }
6102 }
6103
6104
6105 fn expr_to_rust_pattern(&mut self, expr: &Expr) -> String {
6111 match &expr.kind {
6112 ExprKind::Ident(name) => {
6113 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
6115 let enum_str = self.interner.get(enum_name);
6116 let variant_str = self.interner.get(*name);
6117 format!("crate::{}::{}", enum_str, variant_str)
6118 } else {
6119 escape_rust_keyword(self.interner.get(*name))
6120 }
6121 }
6122 _ => self.build_expr_string(expr, None)
6124 }
6125 }
6126}
6127
6128impl<'a, W: Write> CodegenDriver<'a, W> {
6129 pub fn new(
6131 writer: W,
6132 interner: &'a StringInterner,
6133 enum_dict: &'a EnumDict,
6134 macro_ctx: &'a MacroInferContext,
6135 bindings_info: BindingsInfo,
6136 config: CodegenConfig,
6137 ) -> Self {
6138 Self {
6139 writer,
6140 interner,
6141 enum_dict,
6142 macro_ctx,
6143 bindings_info,
6144 config,
6145 stats: CodegenStats::default(),
6146 report: CodegenReport::default(),
6147 used_libc_fns: HashSet::new(),
6148 successfully_generated_inlines: HashSet::new(),
6149 generatable_macros: HashSet::new(),
6150 const_pointer_params: HashMap::new(),
6151 bool_return_macros: HashSet::new(),
6152 perl_threaded: true,
6155 }
6156 }
6157
6158 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
6160 self.perl_threaded = threaded;
6161 self
6162 }
6163
6164 pub fn stats(&self) -> &CodegenStats {
6166 &self.stats
6167 }
6168
6169 pub fn report(&self) -> &CodegenReport {
6171 &self.report
6172 }
6173
6174 pub fn generate(&mut self, result: &InferResult) -> io::Result<()> {
6179 self.perl_threaded = result.perl_build_mode.is_threaded();
6181
6182 let missing_structs = crate::struct_emitter::emit_missing_structs(
6185 &result.fields_dict,
6186 result.rust_decl_dict.as_ref(),
6187 self.interner,
6188 );
6189 let static_arrays = crate::static_array_emitter::emit_static_arrays(
6190 &result.global_const_dict,
6191 &result.fields_dict,
6192 result.rust_decl_dict.as_ref(),
6193 self.interner,
6194 );
6195 for n in &static_arrays.emitted_names {
6199 self.bindings_info.static_arrays.insert(n.clone());
6200 }
6201 for (n, t) in &static_arrays.emitted_types {
6202 self.bindings_info.static_types.insert(n.clone(), t.clone());
6203 }
6204
6205 let mut known_symbols = KnownSymbols::new(result, self.interner);
6207 for n in &missing_structs.emitted_struct_names {
6208 known_symbols.insert(n.clone());
6209 }
6210 for n in &missing_structs.emitted_typedef_names {
6211 known_symbols.insert(n.clone());
6212 }
6213
6214 for (struct_name, methods) in &missing_structs.bitfield_methods {
6218 self.bindings_info
6219 .bitfield_methods
6220 .entry(struct_name.clone())
6221 .or_default()
6222 .extend(methods.iter().cloned());
6223 }
6224 writeln!(self.writer, "// Auto-generated Rust bindings")?;
6229 writeln!(self.writer, "// Generated by libperl-macrogen")?;
6232 writeln!(self.writer)?;
6233
6234 self.generate_use_statements()?;
6236
6237 self.generate_enum_imports(result)?;
6239
6240 if !missing_structs.source.is_empty() {
6242 self.writer.write_all(missing_structs.source.as_bytes())?;
6243 }
6244
6245 if !static_arrays.source.is_empty() {
6247 self.writer.write_all(static_arrays.source.as_bytes())?;
6248 }
6249
6250 self.precompute_macro_generability(result, &known_symbols);
6252
6253 for (&name, info) in &result.infer_ctx.macros {
6255 if info.is_bool_return {
6256 self.bool_return_macros.insert(name);
6257 }
6258 }
6259
6260 if self.config.emit_inline_fns {
6262 self.generate_inline_fns(result, &known_symbols)?;
6263 }
6264
6265 if self.config.emit_macros {
6267 self.generate_macros(result, &known_symbols)?;
6268 }
6269
6270 if !self.used_libc_fns.is_empty() {
6272 let mut fns: Vec<_> = self.used_libc_fns.iter().cloned().collect();
6273 fns.sort();
6274 writeln!(self.writer, "use libc::{{{}}};", fns.join(", "))?;
6275 }
6276
6277 Ok(())
6278 }
6279
6280 fn generate_use_statements(&mut self) -> io::Result<()> {
6282 let statements = if self.config.use_statements.is_empty() {
6283 CodegenConfig::default_use_statements()
6284 } else {
6285 self.config.use_statements.clone()
6286 };
6287
6288 if !statements.is_empty() {
6289 for stmt in &statements {
6290 writeln!(self.writer, "{};", stmt)?;
6291 }
6292 writeln!(self.writer)?;
6293 }
6294
6295 Ok(())
6296 }
6297
6298 fn generate_enum_imports(&mut self, result: &InferResult) -> io::Result<()> {
6302 let enum_names = result.enum_dict.target_enum_names(self.interner);
6303 let bindings_enums = result.rust_decl_dict.as_ref().map(|d| &d.enums);
6304
6305 let filtered_names: Vec<_> = enum_names
6307 .into_iter()
6308 .filter(|name| {
6309 bindings_enums.map_or(true, |enums| enums.contains(*name))
6310 })
6311 .collect();
6312
6313 if !filtered_names.is_empty() {
6314 writeln!(self.writer, "// Enum variant imports")?;
6315 for name in filtered_names {
6316 writeln!(self.writer, "#[allow(unused_imports)]")?;
6317 writeln!(self.writer, "use crate::{}::*;", name)?;
6318 }
6319 writeln!(self.writer)?;
6320 }
6321
6322 Ok(())
6323 }
6324
6325 fn precompute_macro_generability(&mut self, result: &InferResult, known_symbols: &KnownSymbols) {
6331 let macros: Vec<_> = result.infer_ctx.macros.iter()
6333 .filter(|(_, info)| self.should_include_macro(info))
6334 .collect();
6335 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6336
6337 let sorted_names = self.topological_sort_macros(¯os);
6339
6340 for name in sorted_names {
6341 let info = result.infer_ctx.macros.get(&name).unwrap();
6342
6343 if info.apidoc_suppressed {
6349 continue;
6350 }
6351
6352 let has_cascade_failure = info.called_functions.iter().any(|called| {
6357 if included_set.contains(called) {
6358 return result.infer_ctx.macros.get(called)
6359 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6360 .unwrap_or(false)
6361 && !self.generatable_macros.contains(called);
6362 }
6363 false
6364 });
6365 if has_cascade_failure {
6366 continue;
6367 }
6368
6369 let status = self.get_macro_status(info);
6371 if status == GenerateStatus::Success {
6372 let codegen = RustCodegen::new(
6374 self.interner, self.enum_dict, self.macro_ctx,
6375 self.bindings_info.clone(), &known_symbols,
6376 result.rust_decl_dict.as_ref(), Some(&result.inline_fn_dict),
6377 ).with_perl_threaded(self.perl_threaded);
6378 let generated = codegen.generate_macro(info);
6379 if generated.is_complete() && !generated.has_unresolved_names() {
6380 self.generatable_macros.insert(name);
6381 }
6382 }
6383 }
6384 }
6385
6386 pub fn generate_inline_fns(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6393 writeln!(self.writer, "// =============================================================================")?;
6394 writeln!(self.writer, "// Inline Functions")?;
6395 writeln!(self.writer, "// =============================================================================")?;
6396 writeln!(self.writer)?;
6397
6398 let mut fns: Vec<_> = result.inline_fn_dict.iter()
6400 .filter(|(_, func_def)| func_def.is_target)
6401 .collect();
6402 fns.sort_by_key(|(name, _)| self.interner.get(**name));
6403
6404 let inline_set: HashSet<InternedStr> = fns.iter().map(|(n, _)| **n).collect();
6406
6407 enum InlineGenResult {
6409 CallsUnavailable,
6410 ContainsGoto,
6411 UnresolvedNames { code: String, unresolved: Vec<String> },
6412 CodegenError { code: String, errors: Vec<String> },
6413 Incomplete { code: String },
6414 Success { code: String, used_libc: HashSet<String> },
6415 Suppressed { reason: String },
6416 }
6417
6418 let mut gen_results: Vec<(InternedStr, InlineGenResult)> = Vec::new();
6419
6420 for (name, func_def) in &fns {
6421 if result.inline_fn_dict.is_apidoc_suppressed(**name) {
6424 let n_str = self.interner.get(**name);
6425 let reason = result.apidoc_patches.skip_reason(n_str)
6426 .unwrap_or("apidoc skip_codegen")
6427 .to_string();
6428 gen_results.push((**name,
6429 InlineGenResult::Suppressed { reason }));
6430 continue;
6431 }
6432
6433 if result.inline_fn_dict.is_calls_unavailable(**name) {
6435 gen_results.push((**name, InlineGenResult::CallsUnavailable));
6436 continue;
6437 }
6438
6439 if block_items_contain_goto(&func_def.body.items) {
6440 gen_results.push((**name, InlineGenResult::ContainsGoto));
6441 continue;
6442 }
6443
6444 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))
6445 .with_perl_threaded(self.perl_threaded)
6446 .with_dump_ast_for(self.config.dump_ast_for.clone())
6447 .with_dump_types_for(self.config.dump_types_for.clone())
6448 .with_fields_dict(&result.fields_dict)
6449 .with_bool_return(false, self.bool_return_macros.clone());
6450 let generated = codegen.generate_inline_fn(**name, func_def);
6451
6452 if generated.has_unresolved_names() {
6453 gen_results.push((**name, InlineGenResult::UnresolvedNames {
6454 code: generated.code,
6455 unresolved: generated.unresolved_names,
6456 }));
6457 } else if !generated.codegen_errors.is_empty() {
6458 gen_results.push((**name, InlineGenResult::CodegenError {
6459 code: generated.code,
6460 errors: generated.codegen_errors,
6461 }));
6462 } else if generated.is_complete() {
6463 gen_results.push((**name, InlineGenResult::Success {
6464 code: generated.code,
6465 used_libc: generated.used_libc_fns,
6466 }));
6467 } else {
6468 gen_results.push((**name, InlineGenResult::Incomplete {
6469 code: generated.code,
6470 }));
6471 }
6472 }
6473
6474 for (name, gen_result) in &gen_results {
6476 if matches!(gen_result, InlineGenResult::Success { .. }) {
6477 self.successfully_generated_inlines.insert(*name);
6478 }
6479 }
6480
6481 let mut changed = true;
6486 while changed {
6487 changed = false;
6488 let current_success = self.successfully_generated_inlines.clone();
6489 for (name, _) in &gen_results {
6490 if !current_success.contains(name) {
6491 continue;
6492 }
6493 if let Some(calls) = result.inline_fn_dict.get_called_functions(*name) {
6494 let has_unavailable = calls.iter().any(|called| {
6495 if inline_set.contains(called) && !current_success.contains(called) {
6497 return true;
6498 }
6499 if let Some(macro_info) = result.infer_ctx.macros.get(called) {
6501 if macro_info.is_target && self.should_include_macro(macro_info) {
6502 if !self.generatable_macros.contains(called) {
6503 return true;
6504 }
6505 }
6506 }
6507 false
6508 });
6509 if has_unavailable {
6510 self.successfully_generated_inlines.remove(name);
6511 changed = true;
6512 }
6513 }
6514 }
6515 }
6516
6517 for (name, gen_result) in gen_results {
6519 match gen_result {
6520 InlineGenResult::CallsUnavailable => {
6521 let name_str = self.interner.get(name);
6522 let calls = result.inline_fn_dict.get_called_functions(name);
6523 let absent: Vec<String> = calls
6526 .map(|cs| cs.iter()
6527 .filter(|c| {
6528 let fn_name = self.interner.get(**c);
6529 !self.is_function_available(**c, fn_name, result)
6530 })
6531 .map(|c| self.interner.get(*c).to_string())
6532 .collect())
6533 .unwrap_or_default();
6534 let cascade_deps: Vec<String> = calls
6535 .map(|cs| cs.iter()
6536 .filter(|c| {
6537 let is_unavailable_inline = result.inline_fn_dict.get(**c).is_some()
6538 && result.inline_fn_dict.is_unavailable_for_codegen(**c);
6539 let is_unavailable_macro = result.infer_ctx.macros.get(c)
6540 .map(|info| info.is_unavailable_for_codegen())
6541 .unwrap_or(false);
6542 is_unavailable_inline || is_unavailable_macro
6543 })
6544 .map(|c| self.interner.get(*c).to_string())
6545 .collect())
6546 .unwrap_or_default();
6547 let mut cascade_deps = cascade_deps;
6549 cascade_deps.sort();
6550 let mut absent = absent;
6551 absent.sort();
6552 if absent.is_empty() {
6553 writeln!(self.writer,
6554 "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6555 name_str, cascade_deps.join(", "))?;
6556 self.report.record_skip(name_str, format!(
6557 "CASCADE_UNAVAILABLE: dependency not generated: {}",
6558 cascade_deps.join(", ")));
6559 } else {
6560 writeln!(self.writer,
6561 "// [CALLS_UNAVAILABLE] {} - calls unavailable function(s): {}",
6562 name_str, absent.join(", "))?;
6563 self.report.record_skip(name_str, format!(
6564 "CALLS_UNAVAILABLE: calls unavailable function(s): {}",
6565 absent.join(", ")));
6566 }
6567 writeln!(self.writer)?;
6568 self.stats.inline_fns_cascade_unavailable += 1;
6569 }
6570 InlineGenResult::ContainsGoto => {
6571 let name_str = self.interner.get(name);
6572 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6573 writeln!(self.writer)?;
6574 self.report.record_skip(name_str, "CONTAINS_GOTO: excluded (contains goto)");
6575 self.stats.inline_fns_contains_goto += 1;
6576 }
6577 InlineGenResult::Suppressed { reason } => {
6578 let name_str = self.interner.get(name);
6579 writeln!(self.writer,
6580 "// [CODEGEN_SUPPRESSED] {} - inline function (apidoc patch)",
6581 name_str)?;
6582 writeln!(self.writer, "// Reason: {}", reason)?;
6583 writeln!(self.writer)?;
6584 self.report.record_skip(name_str, format!(
6585 "CODEGEN_SUPPRESSED (apidoc patch): {}", reason));
6586 }
6587 InlineGenResult::UnresolvedNames { code, unresolved } => {
6588 let name_str = self.interner.get(name);
6589 let mut unresolved = unresolved.clone();
6590 unresolved.sort(); writeln!(self.writer, "// [UNRESOLVED_NAMES] {} - inline function", name_str)?;
6592 writeln!(self.writer, "// Unresolved: {}", unresolved.join(", "))?;
6593 for line in code.lines() {
6594 writeln!(self.writer, "// {}", line)?;
6595 }
6596 writeln!(self.writer)?;
6597 self.report.record_skip(name_str, format!(
6598 "UNRESOLVED_NAMES: {}", unresolved.join(", ")));
6599 self.stats.inline_fns_unresolved_names += 1;
6600 }
6601 InlineGenResult::CodegenError { code, errors } => {
6602 let name_str = self.interner.get(name);
6603 writeln!(self.writer, "// [CODEGEN_ERROR] {} - inline function", name_str)?;
6604 for err in &errors {
6605 writeln!(self.writer, "// {}", err)?;
6606 }
6607 for line in code.lines() {
6608 writeln!(self.writer, "// {}", line)?;
6609 }
6610 writeln!(self.writer)?;
6611 self.report.record_skip(name_str, format!(
6612 "CODEGEN_ERROR: {}", errors.join("; ")));
6613 }
6614 InlineGenResult::Incomplete { code } => {
6615 let name_str = self.interner.get(name);
6616 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {} - inline function", name_str)?;
6617 for line in code.lines() {
6618 writeln!(self.writer, "// {}", line)?;
6619 }
6620 writeln!(self.writer)?;
6621 self.report.record_skip(name_str, "CODEGEN_INCOMPLETE: type inference incomplete");
6622 self.stats.inline_fns_type_incomplete += 1;
6623 }
6624 InlineGenResult::Success { code, used_libc } => {
6625 if self.successfully_generated_inlines.contains(&name) {
6626 write!(self.writer, "{}", code)?;
6628 self.used_libc_fns.extend(used_libc.iter().cloned());
6629 self.report.record_emit(self.interner.get(name));
6630 self.stats.inline_fns_success += 1;
6631 } else {
6632 let name_str = self.interner.get(name);
6634 let mut unavailable: Vec<String> = result.inline_fn_dict.get_called_functions(name)
6635 .map(|calls| calls.iter()
6636 .filter(|c| inline_set.contains(c) && !self.successfully_generated_inlines.contains(c))
6637 .map(|c| self.interner.get(*c).to_string())
6638 .collect())
6639 .unwrap_or_default();
6640 unavailable.sort(); writeln!(self.writer, "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6642 name_str, unavailable.join(", "))?;
6643 for line in code.lines() {
6644 writeln!(self.writer, "// {}", line)?;
6645 }
6646 writeln!(self.writer)?;
6647 self.report.record_skip(name_str, format!(
6648 "CASCADE_UNAVAILABLE: dependency not generated: {}",
6649 unavailable.join(", ")));
6650 self.stats.inline_fns_cascade_unavailable += 1;
6651 }
6652 }
6653 }
6654 }
6655
6656 writeln!(self.writer)?;
6657 Ok(())
6658 }
6659
6660 pub fn generate_macros(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6662 writeln!(self.writer, "// =============================================================================")?;
6663 writeln!(self.writer, "// Macro Functions")?;
6664 writeln!(self.writer, "// =============================================================================")?;
6665 writeln!(self.writer)?;
6666
6667 let macros: Vec<_> = result.infer_ctx.macros.iter()
6669 .filter(|(_, info)| self.should_include_macro(info))
6670 .collect();
6671 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6672
6673 let sorted_names = self.topological_sort_macros(¯os);
6675
6676 let mut callee_const_params: HashMap<InternedStr, HashSet<usize>> = HashMap::new();
6680 let mut bool_return_macros: HashSet<InternedStr> = HashSet::new();
6681 for (&name, info) in &result.infer_ctx.macros {
6682 if !info.const_pointer_positions.is_empty() {
6683 callee_const_params.insert(name, info.const_pointer_positions.clone());
6684 }
6685 if info.is_bool_return {
6686 bool_return_macros.insert(name);
6687 }
6688 }
6689 self.const_pointer_params = callee_const_params;
6690 self.bool_return_macros = bool_return_macros;
6691
6692 let mut successfully_generated: HashSet<InternedStr> = HashSet::new();
6694
6695 for name in sorted_names {
6696 let info = result.infer_ctx.macros.get(&name).unwrap();
6697
6698 if info.apidoc_suppressed {
6702 let name_str_for_patch = self.interner.get(name);
6703 let reason = result.apidoc_patches.skip_reason(name_str_for_patch)
6704 .unwrap_or("apidoc skip_codegen");
6705 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6706 writeln!(self.writer,
6707 "// [CODEGEN_SUPPRESSED] {}{} - macro function (apidoc patch)",
6708 name_str_for_patch, thx_info)?;
6709 writeln!(self.writer, "// Reason: {}", reason)?;
6710 writeln!(self.writer)?;
6711 self.report.record_skip(name_str_for_patch, format!(
6712 "CODEGEN_SUPPRESSED (apidoc patch): {}", reason));
6713 continue;
6714 }
6715
6716 let unavailable_deps: Vec<String> = info.called_functions.iter()
6722 .filter(|called| {
6723 if included_set.contains(called) {
6725 return result.infer_ctx.macros.get(called)
6726 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6727 .unwrap_or(false)
6728 && !successfully_generated.contains(called);
6729 }
6730 if result.inline_fn_dict.get(**called)
6732 .map(|f| f.is_target)
6733 .unwrap_or(false)
6734 {
6735 return !self.successfully_generated_inlines.contains(called);
6736 }
6737 false
6738 })
6739 .map(|called| self.interner.get(*called).to_string())
6740 .collect();
6741
6742 if !unavailable_deps.is_empty() {
6743 self.generate_macro_cascade_unavailable(info, &unavailable_deps)?;
6744 self.stats.macros_cascade_unavailable += 1;
6745 continue;
6746 }
6747
6748 let status = self.get_macro_status(info);
6750 match status {
6751 GenerateStatus::Success => {
6752 let const_positions = self.const_pointer_params.get(&name)
6754 .cloned().unwrap_or_default();
6755 let is_bool = self.bool_return_macros.contains(&name);
6756 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))
6757 .with_perl_threaded(self.perl_threaded)
6758 .with_dump_ast_for(self.config.dump_ast_for.clone())
6759 .with_dump_types_for(self.config.dump_types_for.clone())
6760 .with_fields_dict(&result.fields_dict)
6761 .with_const_pointer_positions(const_positions)
6762 .with_bool_return(is_bool, self.bool_return_macros.clone());
6763 let generated = codegen.generate_macro(info);
6764
6765 if generated.has_unresolved_names() {
6766 let name_str = self.interner.get(info.name);
6768 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6769 writeln!(self.writer, "// [UNRESOLVED_NAMES] {}{} - macro function", name_str, thx_info)?;
6770 writeln!(self.writer, "// Unresolved: {}", generated.unresolved_names.join(", "))?;
6771 for line in generated.code.lines() {
6772 writeln!(self.writer, "// {}", line)?;
6773 }
6774 writeln!(self.writer)?;
6775 self.report.record_skip(name_str, format!(
6776 "UNRESOLVED_NAMES: {}", generated.unresolved_names.join(", ")));
6777 self.stats.macros_unresolved_names += 1;
6778 } else if !generated.codegen_errors.is_empty() {
6779 let name_str = self.interner.get(info.name);
6781 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6782 writeln!(self.writer, "// [CODEGEN_ERROR] {}{} - macro function", name_str, thx_info)?;
6783 for err in &generated.codegen_errors {
6784 writeln!(self.writer, "// {}", err)?;
6785 }
6786 for line in generated.code.lines() {
6787 writeln!(self.writer, "// {}", line)?;
6788 }
6789 writeln!(self.writer)?;
6790 self.report.record_skip(name_str, format!(
6791 "CODEGEN_ERROR: {}", generated.codegen_errors.join("; ")));
6792 } else if generated.is_complete() {
6793 write!(self.writer, "{}", generated.code)?;
6795 self.used_libc_fns.extend(generated.used_libc_fns.iter().cloned());
6796 self.report.record_emit(self.interner.get(info.name));
6797 self.stats.macros_success += 1;
6798 successfully_generated.insert(name);
6799 } else {
6800 let name_str = self.interner.get(info.name);
6802 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6803 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {}{} - macro function", name_str, thx_info)?;
6804 for line in generated.code.lines() {
6805 writeln!(self.writer, "// {}", line)?;
6806 }
6807 writeln!(self.writer)?;
6808 self.report.record_skip(name_str, "CODEGEN_INCOMPLETE: type inference incomplete");
6809 self.stats.macros_type_incomplete += 1;
6810 }
6811 }
6812 GenerateStatus::ParseFailed => {
6813 self.generate_macro_parse_failed(info)?;
6814 self.report.record_skip(self.interner.get(info.name),
6815 "PARSE_FAILED: macro body does not parse");
6816 self.stats.macros_parse_failed += 1;
6817 }
6818 GenerateStatus::TypeIncomplete => {
6819 self.generate_macro_type_incomplete(info, result)?;
6820 self.report.record_skip(self.interner.get(info.name),
6821 "TYPE_INCOMPLETE: parameter/return type could not be inferred");
6822 self.stats.macros_type_incomplete += 1;
6823 }
6824 GenerateStatus::CallsUnavailable => {
6825 let absent: Vec<&str> = info.called_functions.iter()
6829 .filter(|fn_id| {
6830 let fn_name = self.interner.get(**fn_id);
6831 !self.is_function_available(**fn_id, fn_name, result)
6832 })
6833 .map(|fn_id| self.interner.get(*fn_id))
6834 .collect();
6835 if absent.is_empty() {
6836 let cascade_deps: Vec<String> = info.called_functions.iter()
6838 .filter(|fn_id| {
6839 if let Some(m) = result.infer_ctx.macros.get(*fn_id) {
6840 return m.is_unavailable_for_codegen();
6841 }
6842 if result.inline_fn_dict.get(**fn_id).is_some() {
6843 return result.inline_fn_dict
6844 .is_unavailable_for_codegen(**fn_id);
6845 }
6846 false
6847 })
6848 .map(|fn_id| self.interner.get(*fn_id).to_string())
6849 .collect();
6850 self.generate_macro_cascade_unavailable(info, &cascade_deps)?;
6851 self.stats.macros_cascade_unavailable += 1;
6852 } else {
6853 let mut absent_sorted: Vec<String> =
6854 absent.iter().map(|s| s.to_string()).collect();
6855 absent_sorted.sort();
6856 self.generate_macro_calls_unavailable(info, result)?;
6857 self.report.record_skip(self.interner.get(info.name), format!(
6858 "CALLS_UNAVAILABLE: calls unavailable function(s): {}",
6859 absent_sorted.join(", ")));
6860 self.stats.macros_calls_unavailable += 1;
6861 }
6862 }
6863 GenerateStatus::ContainsGoto => {
6864 let name_str = self.interner.get(info.name);
6865 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6866 writeln!(self.writer)?;
6867 self.report.record_skip(name_str, "CONTAINS_GOTO: excluded (contains goto)");
6868 }
6869 GenerateStatus::GenericUnsupported => {
6870 let name_str = self.interner.get(info.name);
6871 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6872 writeln!(self.writer, "// [GENERIC_UNSUPPORTED] {}{} - Rust cannot cast to generic type T", name_str, thx_info)?;
6873 let const_positions = self.const_pointer_params.get(&name)
6875 .cloned().unwrap_or_default();
6876 let is_bool = self.bool_return_macros.contains(&name);
6877 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))
6878 .with_perl_threaded(self.perl_threaded)
6879 .with_fields_dict(&result.fields_dict)
6880 .with_const_pointer_positions(const_positions)
6881 .with_bool_return(is_bool, self.bool_return_macros.clone());
6882 let generated = codegen.generate_macro(info);
6883 for line in generated.code.lines() {
6884 writeln!(self.writer, "// {}", line)?;
6885 }
6886 writeln!(self.writer)?;
6887 self.report.record_skip(self.interner.get(info.name),
6888 "GENERIC_UNSUPPORTED: Rust cannot cast to generic type T");
6889 self.stats.macros_generic_unsupported += 1;
6890 }
6891 GenerateStatus::Skip => {
6892 self.report.record_skip(self.interner.get(info.name),
6894 "SKIP: excluded from code generation");
6895 }
6896 }
6897 }
6898
6899 Ok(())
6900 }
6901
6902 fn topological_sort_macros(
6906 &self,
6907 macros: &[(&InternedStr, &MacroInferInfo)],
6908 ) -> Vec<InternedStr> {
6909 use std::collections::VecDeque;
6910
6911 let macro_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6912
6913 let mut in_degree: HashMap<InternedStr, usize> = HashMap::new();
6915 let mut dependents: HashMap<InternedStr, Vec<InternedStr>> = HashMap::new();
6916
6917 for (name, _) in macros {
6918 in_degree.insert(**name, 0);
6919 }
6920
6921 for (name, info) in macros {
6922 for used in &info.uses {
6923 if macro_set.contains(used) {
6924 *in_degree.entry(**name).or_insert(0) += 1;
6926 dependents.entry(*used).or_default().push(**name);
6927 }
6928 }
6929 }
6930
6931 let mut queue: VecDeque<InternedStr> = {
6933 let mut zeros: Vec<_> = in_degree.iter()
6934 .filter(|(_, deg)| **deg == 0)
6935 .map(|(name, _)| *name)
6936 .collect();
6937 zeros.sort_by_key(|n| self.interner.get(*n));
6938 zeros.into_iter().collect()
6939 };
6940
6941 let mut result = Vec::with_capacity(macros.len());
6942
6943 while let Some(name) = queue.pop_front() {
6944 result.push(name);
6945 if let Some(deps) = dependents.get(&name) {
6946 let mut newly_ready: Vec<InternedStr> = Vec::new();
6948 for dep in deps {
6949 if let Some(deg) = in_degree.get_mut(dep) {
6950 *deg -= 1;
6951 if *deg == 0 {
6952 newly_ready.push(*dep);
6953 }
6954 }
6955 }
6956 newly_ready.sort_by_key(|n| self.interner.get(*n));
6958 for n in newly_ready {
6959 queue.push_back(n);
6960 }
6961 }
6962 }
6963
6964 if result.len() < macros.len() {
6966 let result_set: HashSet<_> = result.iter().copied().collect();
6967 let mut remaining: Vec<_> = macro_set.iter()
6968 .filter(|n| !result_set.contains(n))
6969 .copied()
6970 .collect();
6971 remaining.sort_by_key(|n| self.interner.get(*n));
6972 result.extend(remaining);
6973 }
6974
6975 result
6976 }
6977
6978 fn generate_macro_cascade_unavailable(
6980 &mut self,
6981 info: &MacroInferInfo,
6982 unavailable_deps: &[String],
6983 ) -> io::Result<()> {
6984 let name_str = self.interner.get(info.name);
6985 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6986 let mut deps: Vec<&String> = unavailable_deps.iter().collect();
6987 deps.sort(); let deps: Vec<&str> = deps.iter().map(|s| s.as_str()).collect();
6989 writeln!(self.writer,
6990 "// [CASCADE_UNAVAILABLE] {}{} - dependency not generated: {}",
6991 name_str, thx_info, deps.join(", "))?;
6992 writeln!(self.writer)?;
6993 self.report.record_skip(name_str, format!(
6994 "CASCADE_UNAVAILABLE: dependency not generated: {}", deps.join(", ")));
6995 Ok(())
6996 }
6997
6998 fn should_include_macro(&self, info: &MacroInferInfo) -> bool {
7000 if !info.is_target {
7002 return false;
7003 }
7004
7005 if !info.has_body {
7007 return false;
7008 }
7009
7010 info.is_function
7012 }
7013
7014 fn get_macro_status(&self, info: &MacroInferInfo) -> GenerateStatus {
7016 if info.calls_unavailable {
7018 return GenerateStatus::CallsUnavailable;
7019 }
7020
7021 if !info.generic_type_params.is_empty() {
7024 return GenerateStatus::GenericUnsupported;
7025 }
7026
7027 match &info.parse_result {
7028 ParseResult::Unparseable(_) => GenerateStatus::ParseFailed,
7029 ParseResult::Statement(items) => {
7030 if block_items_contain_goto(items) {
7032 return GenerateStatus::ContainsGoto;
7033 }
7034 if info.is_fully_confirmed() {
7035 GenerateStatus::Success
7036 } else {
7037 GenerateStatus::TypeIncomplete
7038 }
7039 }
7040 ParseResult::Expression(_) => {
7041 if info.is_fully_confirmed() {
7042 GenerateStatus::Success
7043 } else {
7044 GenerateStatus::TypeIncomplete
7045 }
7046 }
7047 }
7048 }
7049
7050 fn generate_macro_parse_failed(&mut self, info: &MacroInferInfo) -> io::Result<()> {
7052 let name_str = self.interner.get(info.name);
7053
7054 let params_str = if info.is_function {
7056 let params: Vec<_> = info.params.iter()
7057 .map(|p| self.interner.get(p.name).to_string())
7058 .collect();
7059 format!("({})", params.join(", "))
7060 } else {
7061 String::new()
7062 };
7063
7064 writeln!(self.writer, "// [PARSE_FAILED] {}{}", name_str, params_str)?;
7065
7066 if let ParseResult::Unparseable(Some(err_msg)) = &info.parse_result {
7068 writeln!(self.writer, "// Error: {}", err_msg)?;
7069 }
7070
7071 writeln!(self.writer, "// (tokens not available in parsed form)")?;
7073 writeln!(self.writer)?;
7074
7075 Ok(())
7076 }
7077
7078 fn generate_macro_calls_unavailable(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7080 let name_str = self.interner.get(info.name);
7081
7082 let params_str = if info.is_function {
7084 let params: Vec<_> = info.params.iter()
7085 .map(|p| self.interner.get(p.name).to_string())
7086 .collect();
7087 format!("({})", params.join(", "))
7088 } else {
7089 String::new()
7090 };
7091
7092 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
7094
7095 writeln!(self.writer, "// [CALLS_UNAVAILABLE] {}{}{} - calls unavailable function(s)", name_str, params_str, thx_info)?;
7096
7097 let unavailable_fns: Vec<_> = info.called_functions.iter()
7099 .filter(|&fn_id| {
7100 let fn_name = self.interner.get(*fn_id);
7101 !self.is_function_available(*fn_id, fn_name, result)
7103 })
7104 .map(|fn_id| self.interner.get(*fn_id))
7105 .collect();
7106
7107 if !unavailable_fns.is_empty() {
7108 let mut unavailable_fns = unavailable_fns;
7109 unavailable_fns.sort(); writeln!(self.writer, "// Unavailable: {}", unavailable_fns.join(", "))?;
7111 }
7112
7113 writeln!(self.writer)?;
7114
7115 Ok(())
7116 }
7117
7118 fn is_function_available(&self, fn_id: crate::InternedStr, fn_name: &str, result: &InferResult) -> bool {
7120 if result.infer_ctx.macros.contains_key(&fn_id) {
7122 return true;
7123 }
7124
7125 if let Some(rust_decl_dict) = &result.rust_decl_dict {
7127 if rust_decl_dict.fns.contains_key(fn_name) {
7128 return true;
7129 }
7130 }
7131
7132 if result.inline_fn_dict.get(fn_id).is_some() {
7134 return true;
7135 }
7136
7137 let builtin_fns = [
7139 "__builtin_expect",
7140 "__builtin_offsetof",
7141 "offsetof",
7142 "__builtin_types_compatible_p",
7143 "__builtin_constant_p",
7144 "__builtin_choose_expr",
7145 "__builtin_unreachable",
7146 "__builtin_trap",
7147 "__builtin_assume",
7148 "__builtin_bswap16",
7149 "__builtin_bswap32",
7150 "__builtin_bswap64",
7151 "__builtin_popcount",
7152 "__builtin_clz",
7153 "__builtin_ctz",
7154 "pthread_mutex_lock",
7155 "pthread_mutex_unlock",
7156 "pthread_rwlock_rdlock",
7157 "pthread_rwlock_wrlock",
7158 "pthread_rwlock_unlock",
7159 "memchr",
7160 "memcpy",
7161 "memmove",
7162 "memset",
7163 "strlen",
7164 "strcmp",
7165 "strncmp",
7166 "strcpy",
7167 "strncpy",
7168 "ASSERT_IS_LITERAL",
7169 "ASSERT_IS_PTR",
7170 "ASSERT_NOT_PTR",
7171 ];
7172
7173 if builtin_fns.contains(&fn_name) {
7174 return true;
7175 }
7176
7177 false
7178 }
7179
7180 fn generate_macro_type_incomplete(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7182 let name_str = self.interner.get(info.name);
7183
7184 let params_str = if info.is_function {
7186 let params: Vec<_> = info.params.iter()
7187 .map(|p| self.interner.get(p.name).to_string())
7188 .collect();
7189 format!("({})", params.join(", "))
7190 } else {
7191 String::new()
7192 };
7193
7194 writeln!(self.writer, "// [TYPE_INCOMPLETE] {}{}", name_str, params_str)?;
7195
7196 writeln!(self.writer, "// Args status: {:?}, Return status: {:?}",
7198 info.args_infer_status, info.return_infer_status)?;
7199
7200 writeln!(self.writer, "// Typed S-expression:")?;
7202 self.write_typed_sexp_comment(info, result)?;
7203
7204 writeln!(self.writer)?;
7205 Ok(())
7206 }
7207
7208 fn write_typed_sexp_comment(&mut self, info: &MacroInferInfo, _result: &InferResult) -> io::Result<()> {
7210 match &info.parse_result {
7211 ParseResult::Expression(expr) => {
7212 self.write_expr_sexp_comment(expr, info, "// ")?;
7213 }
7214 ParseResult::Statement(block_items) => {
7215 for item in block_items {
7216 if let BlockItem::Stmt(stmt) = item {
7217 self.write_stmt_sexp_comment(stmt, info, "// ")?;
7218 }
7219 }
7220 }
7221 ParseResult::Unparseable(_) => {
7222 writeln!(self.writer, "// (unparseable)")?;
7223 }
7224 }
7225 Ok(())
7226 }
7227
7228 fn write_expr_sexp_comment(&mut self, expr: &Expr, info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7230 let mut buf = Vec::new();
7232 {
7233 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7234 let _ = printer.print_expr(expr);
7235 }
7236
7237 let sexp_str = String::from_utf8_lossy(&buf);
7239 let type_info = self.get_expr_type_info(expr, info);
7240
7241 for line in sexp_str.lines() {
7243 writeln!(self.writer, "{}{}", prefix, line)?;
7244 }
7245 if !type_info.is_empty() {
7246 writeln!(self.writer, "{} :type {}", prefix, type_info)?;
7247 }
7248
7249 Ok(())
7250 }
7251
7252 fn write_stmt_sexp_comment(&mut self, stmt: &Stmt, _info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7254 let mut buf = Vec::new();
7255 {
7256 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7257 let _ = printer.print_stmt(stmt);
7258 }
7259
7260 let sexp_str = String::from_utf8_lossy(&buf);
7261 for line in sexp_str.lines() {
7262 writeln!(self.writer, "{}{}", prefix, line)?;
7263 }
7264
7265 Ok(())
7266 }
7267
7268 fn get_expr_type_info(&self, expr: &Expr, info: &MacroInferInfo) -> String {
7270 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
7272 if let Some(first) = constraints.first() {
7273 return first.ty.to_display_string(self.interner);
7274 }
7275 }
7276 "<unknown>".to_string()
7277 }
7278}
7279
7280#[cfg(test)]
7281mod codegen_report_tests {
7282 use super::*;
7283
7284 fn sample_report() -> CodegenReport {
7285 let mut report = CodegenReport::default();
7286 report.record_emit("CvFILE");
7287 report.record_emit("CvROOT");
7288 report.record_skip("CvSTART", "CASCADE_UNAVAILABLE: dependency not generated: CvROOT");
7289 report
7290 }
7291
7292 #[test]
7293 fn test_check_required_empty_list_is_noop() {
7294 let report = sample_report();
7295 assert!(report.check_required(&[]).is_ok());
7296 }
7297
7298 #[test]
7299 fn test_check_required_emitted_names_pass() {
7300 let report = sample_report();
7301 let required = vec!["CvFILE".to_string(), "CvROOT".to_string()];
7302 assert!(report.check_required(&required).is_ok());
7303 }
7304
7305 #[test]
7306 fn test_check_required_skipped_name_reports_recorded_reason() {
7307 let report = sample_report();
7308 let required = vec!["CvSTART".to_string()];
7309 let err = report.check_required(&required).unwrap_err();
7310 assert_eq!(err.violations.len(), 1);
7311 assert_eq!(err.violations[0].name, "CvSTART");
7312 assert!(err.violations[0].reason.contains("CASCADE_UNAVAILABLE"));
7313 let msg = err.to_string();
7315 assert!(msg.contains("CvSTART"));
7316 assert!(msg.contains("CASCADE_UNAVAILABLE"));
7317 }
7318
7319 #[test]
7320 fn test_check_required_unknown_name_reports_not_a_target() {
7321 let report = sample_report();
7322 let required = vec!["NoSuchFunction".to_string()];
7323 let err = report.check_required(&required).unwrap_err();
7324 assert_eq!(err.violations.len(), 1);
7325 assert!(err.violations[0].reason.contains("not a codegen target"));
7326 }
7327
7328 #[test]
7329 fn test_check_required_collects_all_violations() {
7330 let report = sample_report();
7331 let required = vec![
7332 "CvFILE".to_string(), "CvSTART".to_string(), "NoSuchFunction".to_string(), ];
7336 let err = report.check_required(&required).unwrap_err();
7337 assert_eq!(err.violations.len(), 2);
7338 }
7339}