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 type_str_is_fn_pointer(ty_str: &str) -> bool {
1135 ty_str.contains("fn(") || ty_str.contains("fn (")
1136}
1137
1138fn build_field_type_map(dict: Option<&RustDeclDict>) -> HashMap<String, UnifiedType> {
1139 let mut map: HashMap<String, UnifiedType> = HashMap::new();
1140 let mut conflicts: HashSet<String> = HashSet::new();
1141 if let Some(dict) = dict {
1142 for st in dict.structs.values() {
1143 for field in &st.fields {
1144 if conflicts.contains(&field.name) {
1145 continue;
1146 }
1147 match map.entry(field.name.clone()) {
1148 std::collections::hash_map::Entry::Vacant(e) => {
1149 e.insert(field.uty.clone());
1150 }
1151 std::collections::hash_map::Entry::Occupied(e) => {
1152 if e.get() != &field.uty {
1153 conflicts.insert(field.name.clone());
1154 e.remove();
1155 }
1156 }
1157 }
1158 }
1159 }
1160 for ((_struct, method), ret_ty) in &dict.bitfield_method_types {
1165 if conflicts.contains(method) {
1166 continue;
1167 }
1168 let uty = UnifiedType::from_rust_str(ret_ty);
1169 match map.entry(method.clone()) {
1170 std::collections::hash_map::Entry::Vacant(e) => {
1171 e.insert(uty);
1172 }
1173 std::collections::hash_map::Entry::Occupied(e) => {
1174 if e.get() != &uty {
1175 conflicts.insert(method.clone());
1176 e.remove();
1177 }
1178 }
1179 }
1180 }
1181 }
1182 map
1183}
1184
1185#[derive(Debug, Clone)]
1187pub struct CodegenConfig {
1188 pub emit_inline_fns: bool,
1190 pub emit_macros: bool,
1192 pub include_source_location: bool,
1194 pub use_statements: Vec<String>,
1197 pub dump_ast_for: Option<String>,
1199 pub dump_types_for: Option<String>,
1201}
1202
1203impl Default for CodegenConfig {
1204 fn default() -> Self {
1205 Self {
1206 emit_inline_fns: true,
1207 emit_macros: true,
1208 include_source_location: true,
1209 use_statements: Vec::new(),
1210 dump_ast_for: None,
1211 dump_types_for: None,
1212 }
1213 }
1214}
1215
1216impl CodegenConfig {
1217 pub fn default_use_statements() -> Vec<String> {
1222 vec![
1223 "#[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(),
1226 "#[allow(non_camel_case_types, dead_code)] type size_t = usize".to_string(),
1227 "#[allow(non_camel_case_types, dead_code)] type ssize_t = isize".to_string(),
1228 "#[allow(non_camel_case_types, dead_code)] type SSize_t = isize".to_string(),
1229 ]
1230 }
1231
1232 pub fn with_use_statements(mut self, statements: Vec<String>) -> Self {
1234 self.use_statements = statements;
1235 self
1236 }
1237
1238 pub fn add_use_statement(mut self, statement: impl Into<String>) -> Self {
1240 self.use_statements.push(statement.into());
1241 self
1242 }
1243}
1244
1245#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1247pub enum GenerateStatus {
1248 Success,
1250 ParseFailed,
1252 TypeIncomplete,
1254 CallsUnavailable,
1256 ContainsGoto,
1258 GenericUnsupported,
1260 Skip,
1262}
1263
1264fn stmt_contains_goto(stmt: &Stmt) -> bool {
1266 match stmt {
1267 Stmt::Goto(_, _) => true,
1268 Stmt::Compound(cs) => block_items_contain_goto(&cs.items),
1269 Stmt::If { then_stmt, else_stmt, .. } => {
1270 stmt_contains_goto(then_stmt)
1271 || else_stmt.as_ref().is_some_and(|s| stmt_contains_goto(s))
1272 }
1273 Stmt::Switch { body, .. }
1274 | Stmt::While { body, .. }
1275 | Stmt::For { body, .. } => stmt_contains_goto(body),
1276 Stmt::DoWhile { body, .. } => stmt_contains_goto(body),
1277 Stmt::Label { stmt, .. } => stmt_contains_goto(stmt),
1278 Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => stmt_contains_goto(stmt),
1279 _ => false,
1280 }
1281}
1282
1283fn block_items_contain_goto(items: &[BlockItem]) -> bool {
1285 items.iter().any(|item| match item {
1286 BlockItem::Stmt(stmt) => stmt_contains_goto(stmt),
1287 BlockItem::Decl(_) => false,
1288 })
1289}
1290
1291fn stmt_contains_top_level_break(stmt: &Stmt) -> bool {
1294 match stmt {
1295 Stmt::Break(_) => true,
1296 Stmt::Compound(cs) => cs.items.iter().any(|item| match item {
1297 BlockItem::Stmt(s) => stmt_contains_top_level_break(s),
1298 BlockItem::Decl(_) => false,
1299 }),
1300 Stmt::If { then_stmt, else_stmt, .. } => {
1301 stmt_contains_top_level_break(then_stmt)
1302 || else_stmt.as_ref().is_some_and(|s| stmt_contains_top_level_break(s))
1303 }
1304 Stmt::Label { stmt, .. } => stmt_contains_top_level_break(stmt),
1305 _ => false,
1308 }
1309}
1310
1311#[derive(Debug, Clone, Default)]
1313pub struct CodegenStats {
1314 pub macros_success: usize,
1316 pub macros_parse_failed: usize,
1318 pub macros_type_incomplete: usize,
1320 pub macros_calls_unavailable: usize,
1322 pub macros_cascade_unavailable: usize,
1324 pub macros_generic_unsupported: usize,
1326 pub macros_unresolved_names: usize,
1328 pub inline_fns_success: usize,
1330 pub inline_fns_type_incomplete: usize,
1332 pub inline_fns_unresolved_names: usize,
1334 pub inline_fns_cascade_unavailable: usize,
1336 pub inline_fns_contains_goto: usize,
1338}
1339
1340#[derive(Debug, Clone, Default)]
1346pub struct CodegenReport {
1347 pub emitted: BTreeSet<String>,
1349 pub skipped: BTreeMap<String, String>,
1351}
1352
1353impl CodegenReport {
1354 fn record_emit(&mut self, name: impl Into<String>) {
1355 self.emitted.insert(name.into());
1356 }
1357
1358 fn record_skip(&mut self, name: impl Into<String>, reason: impl Into<String>) {
1359 self.skipped.insert(name.into(), reason.into());
1360 }
1361
1362 pub fn check_required(&self, required: &[String]) -> Result<(), RequireCodegenError> {
1366 let mut violations = Vec::new();
1367 for name in required {
1368 if self.emitted.contains(name) {
1369 continue;
1370 }
1371 let reason = match self.skipped.get(name) {
1372 Some(r) => r.clone(),
1373 None => "not a codegen target (no apidoc declaration or not defined in headers)"
1374 .to_string(),
1375 };
1376 violations.push(RequireViolation {
1377 name: name.clone(),
1378 reason,
1379 });
1380 }
1381 if violations.is_empty() {
1382 Ok(())
1383 } else {
1384 Err(RequireCodegenError { violations })
1385 }
1386 }
1387}
1388
1389#[derive(Debug, Clone)]
1391pub struct RequireCodegenError {
1392 pub violations: Vec<RequireViolation>,
1393}
1394
1395#[derive(Debug, Clone)]
1397pub struct RequireViolation {
1398 pub name: String,
1399 pub reason: String,
1400}
1401
1402impl std::fmt::Display for RequireCodegenError {
1403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1404 writeln!(
1405 f,
1406 "require-codegen-list violation: {} function(s) not generated:",
1407 self.violations.len()
1408 )?;
1409 for v in &self.violations {
1410 writeln!(f, " {} - {}", v.name, v.reason)?;
1411 }
1412 Ok(())
1413 }
1414}
1415
1416impl std::error::Error for RequireCodegenError {}
1417
1418#[derive(Debug, Clone)]
1420pub struct GeneratedCode {
1421 pub code: String,
1423 pub incomplete_count: usize,
1425 pub unresolved_names: Vec<String>,
1427 pub used_libc_fns: HashSet<String>,
1429 pub codegen_errors: Vec<String>,
1431}
1432
1433impl GeneratedCode {
1434 pub fn is_complete(&self) -> bool {
1436 self.incomplete_count == 0
1437 }
1438
1439 pub fn has_unresolved_names(&self) -> bool {
1441 !self.unresolved_names.is_empty()
1442 }
1443}
1444
1445pub struct RustCodegen<'a> {
1451 interner: &'a StringInterner,
1452 enum_dict: &'a EnumDict,
1454 macro_ctx: &'a MacroInferContext,
1456 bindings_info: BindingsInfo,
1458 buffer: String,
1460 incomplete_count: usize,
1462 current_type_param_map: HashMap<InternedStr, String>,
1465 current_literal_string_params: HashSet<InternedStr>,
1467 current_return_type: Option<UnifiedType>,
1469 param_substitutions: HashMap<InternedStr, String>,
1472 current_param_types: HashMap<InternedStr, UnifiedType>,
1475 known_symbols: &'a KnownSymbols,
1477 current_local_names: HashSet<InternedStr>,
1479 unresolved_names: Vec<String>,
1481 used_libc_fns: HashSet<String>,
1483 rust_decl_dict: Option<&'a RustDeclDict>,
1485 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1487 fields_dict: Option<&'a crate::fields_dict::FieldsDict>,
1489 field_type_map: HashMap<String, UnifiedType>,
1491 dump_ast_for: Option<String>,
1493 dump_types_for: Option<String>,
1495 const_pointer_positions: HashSet<usize>,
1497 mut_local_names: HashSet<InternedStr>,
1499 current_local_usage: Option<crate::local_usage::LocalUsageAnalysis>,
1501 unused_param_names: HashSet<InternedStr>,
1503 codegen_errors: Vec<String>,
1505 is_bool_return: bool,
1507 bool_return_macros: HashSet<InternedStr>,
1509 perl_threaded: bool,
1511}
1512
1513pub struct CodegenDriver<'a, W: Write> {
1518 writer: W,
1519 interner: &'a StringInterner,
1520 enum_dict: &'a EnumDict,
1522 macro_ctx: &'a MacroInferContext,
1524 bindings_info: BindingsInfo,
1526 config: CodegenConfig,
1527 stats: CodegenStats,
1528 report: CodegenReport,
1530 used_libc_fns: HashSet<String>,
1532 successfully_generated_inlines: HashSet<InternedStr>,
1534 generatable_macros: HashSet<InternedStr>,
1536 const_pointer_params: HashMap<InternedStr, HashSet<usize>>,
1538 bool_return_macros: HashSet<InternedStr>,
1540 perl_threaded: bool,
1542}
1543
1544impl<'a> RustCodegen<'a> {
1545 pub fn new(
1547 interner: &'a StringInterner,
1548 enum_dict: &'a EnumDict,
1549 macro_ctx: &'a MacroInferContext,
1550 bindings_info: BindingsInfo,
1551 known_symbols: &'a KnownSymbols,
1552 rust_decl_dict: Option<&'a RustDeclDict>,
1553 inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1554 ) -> Self {
1555 Self {
1556 interner,
1557 enum_dict,
1558 macro_ctx,
1559 bindings_info,
1560 buffer: String::new(),
1561 incomplete_count: 0,
1562 current_type_param_map: HashMap::new(),
1563 current_literal_string_params: HashSet::new(),
1564 current_return_type: None,
1565 param_substitutions: HashMap::new(),
1566 current_param_types: HashMap::new(),
1567 known_symbols,
1568 current_local_names: HashSet::new(),
1569 unresolved_names: Vec::new(),
1570 used_libc_fns: HashSet::new(),
1571 rust_decl_dict,
1572 inline_fn_dict,
1573 fields_dict: None,
1574 field_type_map: build_field_type_map(rust_decl_dict),
1575 dump_ast_for: None,
1576 dump_types_for: None,
1577 const_pointer_positions: HashSet::new(),
1578 is_bool_return: false,
1579 bool_return_macros: HashSet::new(),
1580 mut_local_names: HashSet::new(),
1581 current_local_usage: None,
1582 unused_param_names: HashSet::new(),
1583 codegen_errors: Vec::new(),
1584 perl_threaded: true,
1587 }
1588 }
1589
1590 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
1592 self.perl_threaded = threaded;
1593 self
1594 }
1595
1596 pub fn with_dump_ast_for(mut self, name: Option<String>) -> Self {
1598 self.dump_ast_for = name;
1599 self
1600 }
1601
1602 pub fn with_dump_types_for(mut self, name: Option<String>) -> Self {
1603 self.dump_types_for = name;
1604 self
1605 }
1606
1607 pub fn with_fields_dict(mut self, dict: &'a crate::fields_dict::FieldsDict) -> Self {
1609 self.fields_dict = Some(dict);
1610 for (_name, def) in dict.iter_struct_defs() {
1615 for m in &def.members {
1616 let member_name = self.interner.get(m.name).to_string();
1617 if self.field_type_map.contains_key(&member_name) {
1618 continue;
1619 }
1620 let rust_ty = m.type_repr.to_rust_string(self.interner);
1621 self.field_type_map
1622 .insert(member_name, UnifiedType::from_rust_str(&rust_ty));
1623 }
1624 }
1625 self
1626 }
1627
1628 pub fn with_const_pointer_positions(mut self, positions: HashSet<usize>) -> Self {
1630 self.const_pointer_positions = positions;
1631 self
1632 }
1633
1634 pub fn with_bool_return(mut self, is_bool: bool, bool_macros: HashSet<InternedStr>) -> Self {
1636 self.is_bool_return = is_bool;
1637 self.bool_return_macros = bool_macros;
1638 self
1639 }
1640
1641 fn dump_type_info(&self, name_str: &str, info: &MacroInferInfo, params_str: &str, return_type: &str) {
1644 eprintln!("=== Type dump for {} ===", name_str);
1645 for (i, p) in info.params.iter().enumerate() {
1647 let pname = self.interner.get(p.name);
1648 let is_const = info.const_pointer_positions.contains(&i);
1649 let expr_ids: Vec<_> = info.type_env.param_to_exprs
1651 .get(&p.name)
1652 .map(|ids| ids.iter().cloned().collect())
1653 .unwrap_or_default();
1654 let mut all_ids = expr_ids;
1655 all_ids.push(p.expr_id());
1656 eprintln!(" param[{}] {} (const_position={})", i, pname, is_const);
1657 for eid in &all_ids {
1658 if let Some(constraints) = info.type_env.expr_constraints.get(eid) {
1659 for c in constraints {
1660 eprintln!(" constraint: tier={} rust={} context={} source={:?}",
1661 c.ty.confidence_tier(),
1662 c.ty.to_rust_string(self.interner),
1663 c.context,
1664 match &c.ty {
1665 crate::type_repr::TypeRepr::CType { source, .. } => format!("{:?}", source),
1666 crate::type_repr::TypeRepr::RustType { source, .. } => format!("{:?}", source),
1667 crate::type_repr::TypeRepr::Inferred(i) => format!("Inferred({:?})", std::mem::discriminant(i)),
1668 }
1669 );
1670 }
1671 }
1672 }
1673 }
1674 eprintln!(" params_str: {}", params_str);
1675 eprintln!(" return_type: {}", return_type);
1677 eprintln!(" is_bool_return: {}", info.is_bool_return);
1678 if let Some(ty) = info.get_return_type() {
1679 eprintln!(" return TypeRepr: tier={} rust={}", ty.confidence_tier(), ty.to_rust_string(self.interner));
1680 }
1681 if !info.type_env.return_constraints.is_empty() {
1683 eprintln!(" return_constraints:");
1684 for c in &info.type_env.return_constraints {
1685 eprintln!(" tier={} rust={} context={}", c.ty.confidence_tier(), c.ty.to_rust_string(self.interner), c.context);
1686 }
1687 }
1688 if let ParseResult::Expression(ref expr) = info.parse_result {
1690 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
1691 eprintln!(" root expr constraints:");
1692 for c in constraints {
1693 eprintln!(" tier={} rust={} context={}",
1694 c.ty.confidence_tier(),
1695 c.ty.to_rust_string(self.interner),
1696 c.context,
1697 );
1698 }
1699 }
1700 }
1701 eprintln!("=== End type dump ===");
1702 }
1703
1704 fn dump_ast_comment_for_expr(&mut self, name_str: &str, parse_result: &ParseResult) {
1705 if self.dump_ast_for.as_deref() != Some(name_str) {
1706 return;
1707 }
1708 let sexp = match parse_result {
1709 ParseResult::Expression(expr) => {
1710 let mut buf = Vec::new();
1711 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1712 let _ = printer.print_expr(expr);
1713 String::from_utf8_lossy(&buf).into_owned()
1714 }
1715 ParseResult::Statement(block_items) => {
1716 let mut buf = Vec::new();
1717 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1718 for item in block_items {
1719 if let BlockItem::Stmt(stmt) = item {
1720 let _ = printer.print_stmt(stmt);
1721 } else if let BlockItem::Decl(decl) = item {
1722 let _ = printer.print_declaration(decl);
1723 }
1724 }
1725 String::from_utf8_lossy(&buf).into_owned()
1726 }
1727 ParseResult::Unparseable(msg) => {
1728 format!("(unparseable: {})", msg.as_deref().unwrap_or("unknown"))
1729 }
1730 };
1731 self.writeln(&format!("// [AST dump for {}]", name_str));
1732 for line in sexp.lines() {
1733 self.writeln(&format!("// {}", line));
1734 }
1735 }
1736
1737 fn dump_ast_comment_for_body(&mut self, name_str: &str, body: &CompoundStmt) {
1739 if self.dump_ast_for.as_deref() != Some(name_str) {
1740 return;
1741 }
1742 let mut buf = Vec::new();
1743 let mut printer = SexpPrinter::new(&mut buf, self.interner);
1744 for item in &body.items {
1745 match item {
1746 BlockItem::Stmt(stmt) => { let _ = printer.print_stmt(stmt); }
1747 BlockItem::Decl(decl) => { let _ = printer.print_declaration(decl); }
1748 }
1749 }
1750 let sexp = String::from_utf8_lossy(&buf).into_owned();
1751 self.writeln(&format!("// [AST dump for {}]", name_str));
1752 for line in sexp.lines() {
1753 self.writeln(&format!("// {}", line));
1754 }
1755 }
1756
1757 fn try_expand_call_as_lvalue_syn(&mut self, func: &Expr, args: &[Expr],
1761 info: Option<&MacroInferInfo>) -> Option<syn::Expr> {
1762 if let ExprKind::Ident(name) = &func.kind {
1763 if self.should_emit_as_macro_call(*name) {
1764 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
1765 if let ParseResult::Expression(body) = ¯o_info.parse_result {
1766 let body = body.clone();
1767 let saved_params = std::mem::take(&mut self.param_substitutions);
1768 for (i, param) in macro_info.params.iter().enumerate() {
1769 if let Some(arg) = args.get(i) {
1770 let arg_syn = self.build_syn_expr(arg, info);
1771 let arg_str = crate::syn_codegen::expr_to_string(&arg_syn);
1772 self.param_substitutions.insert(param.name, arg_str);
1773 }
1774 }
1775 let body_syn = self.build_syn_expr(&body, info);
1776 self.param_substitutions = saved_params;
1777 return Some(body_syn);
1778 }
1779 }
1780 }
1781 }
1782 None
1783 }
1784
1785
1786 fn wrap_as_bool_condition_inline(&self, expr: &Expr, expr_str: &str) -> String {
1788 self.wrap_as_bool_condition(expr, expr_str, None)
1789 }
1790
1791 fn infer_expr_type_inline(&self, expr: &Expr) -> Option<UnifiedType> {
1793 self.infer_expr_type_unified(expr, None)
1794 }
1795
1796 fn type_name_to_type_str_readonly(&self, type_name: &crate::ast::TypeName) -> String {
1798 let pointer_count = type_name.declarator.as_ref()
1800 .map(|d| d.derived.iter().filter(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer(_))).count())
1801 .unwrap_or(0);
1802 let is_const_ptr = pointer_count == 1 && type_name.specs.qualifiers.is_const;
1808 let base = self.base_type_str_readonly(&type_name.specs.type_specs);
1810 let mut result = base;
1812 for _ in 0..pointer_count {
1813 let prefix = if is_const_ptr { "*const " } else { "*mut " };
1814 result = format!("{}{}", prefix, result);
1815 }
1816 result
1817 }
1818
1819 fn base_type_str_readonly(&self, type_specs: &[TypeSpec]) -> String {
1821 for spec in type_specs {
1823 if let TypeSpec::TypedefName(name) = spec {
1824 return self.interner.get(*name).to_string();
1825 }
1826 }
1827 for spec in type_specs {
1829 match spec {
1830 TypeSpec::Struct(s) | TypeSpec::Union(s) => {
1831 if let Some(n) = &s.name {
1832 return self.interner.get(*n).to_string();
1833 }
1834 }
1835 TypeSpec::Enum(e) => {
1836 if let Some(n) = &e.name {
1837 return self.interner.get(*n).to_string();
1838 }
1839 }
1840 _ => {}
1841 }
1842 }
1843 let mut is_void = false;
1844 let mut is_char = false;
1845 let mut is_int = false;
1846 let mut is_short = false;
1847 let mut is_long = 0usize;
1848 let mut is_unsigned = false;
1849 for spec in type_specs {
1850 match spec {
1851 TypeSpec::Void => is_void = true,
1852 TypeSpec::Char => is_char = true,
1853 TypeSpec::Int => is_int = true,
1854 TypeSpec::Short => is_short = true,
1855 TypeSpec::Long => is_long += 1,
1856 TypeSpec::Unsigned => is_unsigned = true,
1857 TypeSpec::Signed => {}
1858 TypeSpec::Bool => return "bool".to_string(),
1859 _ => {}
1860 }
1861 }
1862 if is_void { return "c_void".to_string(); }
1863 if is_char { return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() }; }
1864 if is_short { return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() }; }
1865 if is_long >= 2 { return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() }; }
1866 if is_long == 1 { return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() }; }
1867 if is_int || is_unsigned { return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() }; }
1868 "c_int".to_string()
1869 }
1870
1871 fn infer_expr_type(&self, expr: &Expr, info: &MacroInferInfo) -> Option<UnifiedType> {
1873 self.infer_expr_type_unified(expr, Some(info))
1874 }
1875
1876 fn infer_expr_type_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> Option<UnifiedType> {
1885 match &expr.kind {
1886 ExprKind::Ident(name) => {
1887 if let Some(ut) = self.current_param_types.get(name) {
1889 return Some(ut.clone());
1890 }
1891 if let Some(info) = info {
1893 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
1895 let mut best: Option<(UnifiedType, u8)> = None;
1896 for expr_id in expr_ids {
1897 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
1898 for c in constraints {
1899 if c.ty.is_void() { continue; }
1900 let tier = c.ty.confidence_tier();
1901 if best.is_none() || tier < best.as_ref().unwrap().1 {
1902 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
1903 }
1904 }
1905 }
1906 }
1907 if let Some((ut, _)) = best {
1908 return Some(ut);
1909 }
1910 }
1911 if let Some(constraints) = info.type_env.param_constraints.get(name) {
1913 let mut best: Option<(UnifiedType, u8)> = None;
1914 for c in constraints {
1915 if c.ty.is_void() { continue; }
1916 let tier = c.ty.confidence_tier();
1917 if best.is_none() || tier < best.as_ref().unwrap().1 {
1918 best = Some((UnifiedType::from_rust_str(&c.ty.to_rust_string(self.interner)), tier));
1919 }
1920 }
1921 if let Some((ut, _)) = best {
1922 return Some(ut);
1923 }
1924 }
1925 }
1926 if let Some(dict) = self.rust_decl_dict {
1928 let name_str = self.interner.get(*name);
1929 if let Some(c) = dict.consts.get(name_str) {
1930 return Some(c.uty.clone());
1931 }
1932 if let Some(ty_str) = dict.static_types.get(name_str) {
1934 return Some(UnifiedType::from_rust_str(ty_str));
1935 }
1936 }
1937 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
1941 let enum_str = self.interner.get(enum_name).to_string();
1942 return Some(UnifiedType::Named(enum_str));
1943 }
1944 None
1945 }
1946 ExprKind::Cast { type_name, .. } => {
1947 Some(UnifiedType::from_rust_str(&self.type_name_to_type_str_readonly(type_name)))
1948 }
1949 ExprKind::Member { expr: base, member } | ExprKind::PtrMember { expr: base, member } => {
1950 let resolve_struct_name = |this: &Self| -> Option<String> {
1955 if let Some(info_ref) = info {
1957 if let Some(constraints) = info_ref.type_env.expr_constraints.get(&base.id) {
1958 if let Some(base_ty) = constraints.first().map(|c| &c.ty) {
1959 let sn = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
1960 base_ty.pointee_name()
1961 } else {
1962 base_ty.type_name()
1963 };
1964 if let Some(n) = sn {
1965 return Some(this.interner.get(n).to_string());
1966 }
1967 }
1968 }
1969 }
1970 let base_ut = this.infer_expr_type_unified(base, info)?;
1973 let target = if matches!(&expr.kind, ExprKind::PtrMember { .. }) {
1974 base_ut.inner_type()?
1975 } else {
1976 &base_ut
1977 };
1978 if let UnifiedType::Named(n) = target {
1979 return Some(n.clone());
1980 }
1981 None
1982 };
1983
1984 let member_str = self.interner.get(*member);
1985 let fd_ty: Option<UnifiedType> = self.fields_dict.and_then(|fd| {
1992 let struct_name_str = resolve_struct_name(self)?;
1993 let struct_name = self.interner.lookup(&struct_name_str)?;
1994 let member_ty = fd.member_type(struct_name, *member)?;
1995 let rust_ty = member_ty.to_rust_string(self.interner);
1996 if rust_ty.contains("/* fn */") {
1997 return None;
1998 }
1999 Some(UnifiedType::from_rust_str(&rust_ty))
2000 });
2001 let ftm_ty = self.field_type_map.get(member_str).cloned();
2002 match (&fd_ty, &ftm_ty) {
2005 (Some(fd_ut), Some(ftm_ut))
2006 if fd_ut.is_pointer() && ftm_ut.to_rust_string().starts_with('[') =>
2007 {
2008 return ftm_ty;
2009 }
2010 _ => {}
2011 }
2012 fd_ty.or(ftm_ty)
2013 }
2014 ExprKind::Deref(inner) => {
2015 let inner_ut = self.infer_expr_type_unified(inner, info)?;
2016 inner_ut.inner_type().cloned()
2017 }
2018 ExprKind::Index { expr: base, .. } => {
2019 let base_ut = self.infer_expr_type_unified(base, info)?;
2022 base_ut.inner_type().cloned()
2023 }
2024 ExprKind::Binary { op, lhs, rhs } => {
2025 match op {
2026 BinOp::Shl | BinOp::Shr => self.infer_expr_type_unified(lhs, info),
2027 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => {
2028 let lt = self.infer_expr_type_unified(lhs, info);
2029 let rt = self.infer_expr_type_unified(rhs, info);
2030 match (<, &rt) {
2031 (Some(l), Some(r)) => {
2032 let ls = l.to_rust_string();
2033 let rs = r.to_rust_string();
2034 wider_integer_type(&ls, &rs)
2035 .map(|w| UnifiedType::from_rust_str(w))
2036 .or(lt)
2037 }
2038 (Some(_), None) => lt,
2039 (None, Some(_)) => rt,
2040 _ => None,
2041 }
2042 }
2043 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt
2044 | BinOp::Le | BinOp::Ge | BinOp::LogAnd | BinOp::LogOr => {
2045 Some(UnifiedType::Bool)
2046 }
2047 _ => {
2048 if *op == BinOp::Sub {
2051 let lp = self.is_pointer_expr_unified(lhs, info)
2052 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
2053 let rp = self.is_pointer_expr_unified(rhs, info)
2054 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
2055 if lp && rp {
2056 return Some(UnifiedType::Named("isize".to_string()));
2057 }
2058 }
2059 let lt = self.infer_expr_type_unified(lhs, info);
2060 if lt.is_some() { return lt; }
2061 self.infer_expr_type_unified(rhs, info)
2062 }
2063 }
2064 }
2065 ExprKind::BitNot(inner) | ExprKind::UnaryMinus(inner) => self.infer_expr_type_unified(inner, info),
2066 ExprKind::CharLit(_) => Some(UnifiedType::from_rust_str("i8")),
2067 ExprKind::UIntLit(_) => Some(UnifiedType::Int { signed: false, size: crate::unified_type::IntSize::LongLong }),
2068 ExprKind::Sizeof(_) | ExprKind::SizeofType(_) => Some(UnifiedType::Named("usize".to_string())),
2073 ExprKind::Call { func, .. } => {
2074 if let ExprKind::Member { expr: receiver, member, .. } = &func.kind {
2076 let method_name = self.interner.get(*member);
2077 if matches!(method_name, "offset" | "wrapping_add" | "wrapping_sub" | "wrapping_offset") {
2078 return self.infer_expr_type_unified(receiver, info);
2079 }
2080 }
2081 if let ExprKind::Ident(name) = &func.kind {
2082 let func_name = self.interner.get(*name);
2083 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2084 return Some(ret_ut.clone());
2085 }
2086 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2088 if let Some(ty) = macro_info.get_return_type() {
2089 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2090 }
2091 }
2092 if let Some(dict) = self.inline_fn_dict {
2094 if let Some(func_def) = dict.get(*name) {
2095 let base = self.base_type_str_readonly(&func_def.specs.type_specs);
2097 let mut result = base;
2098 let pointer_count = func_def.declarator.derived.iter()
2099 .take_while(|d| !matches!(d, crate::ast::DerivedDecl::Function(_)))
2100 .filter(|d| matches!(d, crate::ast::DerivedDecl::Pointer(_)))
2101 .count();
2102 let is_const_ptr = pointer_count == 1
2103 && func_def.specs.qualifiers.is_const;
2104 for _ in 0..pointer_count {
2105 let prefix = if is_const_ptr { "*const " } else { "*mut " };
2106 result = format!("{}{}", prefix, result);
2107 }
2108 return Some(UnifiedType::from_rust_str(&result));
2109 }
2110 }
2111 }
2112 None
2113 }
2114 ExprKind::MacroCall { name, expanded, .. } => {
2115 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2116 if let Some(ty) = macro_info.get_return_type() {
2117 return Some(UnifiedType::from_rust_str(&ty.to_rust_string(self.interner)));
2118 }
2119 }
2120 self.infer_expr_type_unified(expanded, info)
2121 }
2122 ExprKind::Conditional { then_expr, else_expr, .. } => {
2123 if is_null_literal(then_expr) {
2124 return self.infer_expr_type_unified(else_expr, info);
2125 }
2126 if is_null_literal(else_expr) {
2127 return self.infer_expr_type_unified(then_expr, info);
2128 }
2129 let tt = self.infer_expr_type_unified(then_expr, info);
2130 let et = self.infer_expr_type_unified(else_expr, info);
2131 match (&tt, &et) {
2132 (Some(t), Some(e)) if t.is_void_pointer() && e.is_concrete_pointer() => et,
2133 (Some(t), Some(e)) if e.is_void_pointer() && t.is_concrete_pointer() => tt,
2134 (Some(_), _) => tt,
2135 (None, _) => et,
2136 }
2137 }
2138 _ => None,
2139 }
2140 }
2141
2142 fn is_pointer_expr_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2144 match &expr.kind {
2145 ExprKind::Ident(name) => {
2146 if let Some(ut) = self.current_param_types.get(name) {
2147 return ut.is_pointer();
2148 }
2149 if let Some(info) = info {
2150 if let Some(constraints) = info.type_env.param_constraints.get(name) {
2151 for c in constraints {
2152 if is_type_repr_pointer(&c.ty) {
2153 return true;
2154 }
2155 }
2156 }
2157 if let Some(expr_ids) = info.type_env.param_to_exprs.get(name) {
2158 for expr_id in expr_ids {
2159 if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
2160 for c in constraints {
2161 if is_type_repr_pointer(&c.ty) {
2162 return true;
2163 }
2164 }
2165 }
2166 }
2167 }
2168 }
2169 false
2170 }
2171 ExprKind::Cast { type_name, .. } => {
2172 type_name.declarator.as_ref()
2173 .map(|d| d.derived.iter().any(|dd| matches!(dd, crate::ast::DerivedDecl::Pointer { .. })))
2174 .unwrap_or(false)
2175 }
2176 ExprKind::AddrOf(_) => true,
2177 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => {
2178 let member_str = self.interner.get(*member);
2179 self.field_type_map.get(member_str).is_some_and(|ut| ut.is_pointer())
2180 }
2181 ExprKind::Deref(inner) => {
2182 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
2183 if let Some(derefed) = ut.inner_type() {
2184 return derefed.is_pointer();
2185 }
2186 }
2187 false
2188 }
2189 ExprKind::Call { func, .. } | ExprKind::MacroCall { expanded: func, .. } => {
2190 let check_func = match &expr.kind {
2191 ExprKind::MacroCall { name, .. } => {
2192 if let Some(callee) = self.macro_ctx.macros.get(name) {
2193 for c in &callee.type_env.return_constraints {
2194 if is_type_repr_pointer(&c.ty) { return true; }
2195 }
2196 }
2197 func
2198 }
2199 _ => func,
2200 };
2201 if let ExprKind::Ident(name) = &check_func.kind {
2202 if let Some(callee) = self.macro_ctx.macros.get(name) {
2203 for c in &callee.type_env.return_constraints {
2204 if is_type_repr_pointer(&c.ty) { return true; }
2205 }
2206 }
2207 if let Some(ret_ut) = self.get_callee_return_type(self.interner.get(*name)) {
2208 return ret_ut.is_pointer();
2209 }
2210 }
2211 false
2212 }
2213 ExprKind::Binary { op, lhs, rhs } => {
2214 match op {
2215 BinOp::Add => self.is_pointer_expr_unified(lhs, info) || self.is_pointer_expr_unified(rhs, info),
2216 BinOp::Sub => self.is_pointer_expr_unified(lhs, info) && !self.is_pointer_expr_unified(rhs, info),
2217 _ => false,
2218 }
2219 }
2220 _ => false,
2221 }
2222 }
2223
2224 fn is_option_fn_pointer_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2231 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2235 let member_str = self.interner.get(*member);
2236 if let Some(ut) = self.field_type_map.get(member_str) {
2237 let ty_str = ut.to_rust_string();
2238 if type_str_is_fn_pointer(&ty_str) {
2239 return true;
2240 }
2241 if let Some(dict) = self.rust_decl_dict {
2242 if let Some(alias) = dict.types.get(&ty_str) {
2243 if type_str_is_fn_pointer(&alias.ty) {
2244 return true;
2245 }
2246 }
2247 }
2248 }
2249 }
2250 let Some(ut) = self.infer_expr_type_unified(expr, info) else { return false };
2251 let ty_str = ut.to_rust_string();
2252 if type_str_is_fn_pointer(&ty_str) {
2253 return true;
2254 }
2255 if let Some(dict) = self.rust_decl_dict {
2257 if let Some(alias) = dict.types.get(&ty_str) {
2258 if type_str_is_fn_pointer(&alias.ty) {
2259 return true;
2260 }
2261 }
2262 }
2263 false
2264 }
2265
2266 fn wrap_as_bool_condition(&self, expr: &Expr, expr_str: &str, info: Option<&MacroInferInfo>) -> String {
2268 if self.is_bool_expr_with_dict(expr) {
2269 return expr_str.to_string();
2270 }
2271 if let ExprKind::Ident(name) = &expr.kind {
2273 if let Some(ut) = self.current_param_types.get(name) {
2274 if ut.is_bool() {
2275 return expr_str.to_string();
2276 }
2277 }
2278 }
2279 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2281 let member_str = self.interner.get(*member);
2282 if let Some(ut) = self.field_type_map.get(member_str) {
2283 if ut.is_bool() {
2284 return expr_str.to_string();
2285 }
2286 }
2287 }
2288 if let ExprKind::Call { func, args, .. } = &expr.kind {
2290 if let ExprKind::Ident(name) = &func.kind {
2291 if self.interner.get(*name) == "__builtin_expect" && !args.is_empty() {
2292 return self.wrap_as_bool_condition(&args[0], expr_str, info);
2293 }
2294 }
2295 }
2296 if expr_str.ends_with(" as bool)") || expr_str.ends_with("!= 0)") || expr_str.ends_with(".is_null()") {
2297 return expr_str.to_string();
2298 }
2299 if self.is_option_fn_pointer_expr(expr, info) {
2302 return format!("{}.is_some()", expr_str);
2303 }
2304 if self.is_pointer_expr_unified(expr, info)
2305 || self.infer_expr_type_unified(expr, info).is_some_and(|ut| ut.is_pointer()) {
2306 return format!("!({}).is_null()", expr_str);
2311 }
2312 format!("({} != 0)", strip_outer_parens(expr_str))
2313 }
2314
2315 fn needs_my_perl_for_call(&self, func_name: crate::InternedStr, actual_arg_count: usize) -> bool {
2322 if !self.perl_threaded {
2326 return false;
2327 }
2328 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2329 if callee_info.is_thx_dependent {
2330 let expected_count = callee_info.params.len() + 1;
2332 return actual_arg_count + 1 == expected_count;
2334 }
2335 }
2336 false
2337 }
2338
2339 fn is_static_array_expr(&self, expr: &Expr) -> bool {
2341 if let ExprKind::Ident(name) = &expr.kind {
2342 let name_str = self.interner.get(*name);
2343 self.bindings_info.static_arrays.contains(name_str)
2344 } else {
2345 false
2346 }
2347 }
2348
2349 fn is_array_like_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2357 if self.is_static_array_expr(expr) {
2358 return true;
2359 }
2360 if let ExprKind::Member { expr: base, member }
2362 | ExprKind::PtrMember { expr: base, member } = &expr.kind
2363 {
2364 if let (Some(fd), Some(info)) = (self.fields_dict, info) {
2365 if let Some(constraints) = info.type_env.expr_constraints.get(&base.id) {
2366 if let Some(base_type) = constraints.first().map(|c| &c.ty) {
2367 let struct_name = match &expr.kind {
2368 ExprKind::PtrMember { .. } => base_type.pointee_name(),
2369 _ => base_type.type_name(),
2370 };
2371 if let Some(sn) = struct_name {
2372 if fd.is_flexible_array_field(sn, *member) {
2373 return false;
2374 }
2375 }
2376 }
2377 }
2378 }
2379 }
2380 if let Some(ut) = self.infer_expr_type_unified(expr, info) {
2381 let s = ut.to_rust_string();
2382 if s.starts_with('[') && s.contains(';') {
2383 return true;
2384 }
2385 }
2386 false
2387 }
2388
2389 fn is_bitfield_method(&self, member_name: &str) -> bool {
2393 self.bindings_info.bitfield_methods.values()
2394 .any(|methods| methods.contains(member_name))
2395 }
2396
2397 fn get_callee_generic_params(&self, func_name: InternedStr) -> Option<&HashMap<i32, String>> {
2399 let callee_info = self.macro_ctx.macros.get(&func_name)?;
2400 if callee_info.generic_type_params.is_empty() {
2401 return None;
2402 }
2403 if callee_info.generic_type_params.keys().any(|&k| k >= 0) {
2404 Some(&callee_info.generic_type_params)
2405 } else {
2406 None
2407 }
2408 }
2409
2410 fn is_enum_cast_target(&self, type_name: &crate::ast::TypeName) -> bool {
2412 for spec in &type_name.specs.type_specs {
2413 match spec {
2414 TypeSpec::TypedefName(name) => return self.enum_dict.is_target_enum(*name),
2415 TypeSpec::Enum(_) => return true,
2416 _ => {}
2417 }
2418 }
2419 false
2420 }
2421
2422 fn callee_expects_literal_string(&self, func_name: InternedStr, arg_index: usize) -> bool {
2424 if let Some(callee_info) = self.macro_ctx.macros.get(&func_name) {
2425 return callee_info.literal_string_params.contains(&arg_index);
2426 }
2427 false
2428 }
2429
2430 fn get_callee_param_type(&self, func_name: &str, arg_index: usize) -> Option<&UnifiedType> {
2432 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2433 f.params.get(arg_index).map(|p| &p.uty)
2434 })
2435 }
2436
2437 fn get_callee_param_type_extended(&mut self, func_name: &str, arg_index: usize) -> Option<UnifiedType> {
2439 if let Some(ut) = libc_fn_param_type(func_name, arg_index) {
2443 return Some(ut);
2444 }
2445 if let Some(ut) = self.get_callee_param_type(func_name, arg_index) {
2447 return Some(ut.clone());
2448 }
2449 if let Some(interned) = self.interner.lookup(func_name) {
2450 if let Some(dict) = self.inline_fn_dict {
2452 if let Some(func_def) = dict.get(interned) {
2453 for d in &func_def.declarator.derived {
2454 if let DerivedDecl::Function(param_list) = d {
2455 if let Some(param) = param_list.params.get(arg_index) {
2456 let ty = self.param_type_only(param);
2457 return Some(UnifiedType::from_rust_str(&ty));
2458 }
2459 break;
2460 }
2461 }
2462 }
2463 }
2464 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2466 let macro_param_idx = if self.perl_threaded && macro_info.is_thx_dependent {
2469 if arg_index == 0 {
2470 return Some(UnifiedType::from_rust_str("*mut PerlInterpreter"));
2471 }
2472 arg_index - 1
2473 } else {
2474 arg_index
2475 };
2476 if let Some(param) = macro_info.params.get(macro_param_idx) {
2477 if let Some(mut ty) = best_constraint_for_macro_param(macro_info, param) {
2481 let should_be_const = macro_info
2484 .const_pointer_positions
2485 .contains(¯o_param_idx);
2486 if should_be_const {
2487 ty.make_outer_pointer_const();
2488 } else if ty.has_outer_pointer() {
2489 ty.make_outer_pointer_mut();
2490 }
2491 let rust_ty = ty.to_rust_string(self.interner);
2492 return Some(UnifiedType::from_rust_str(&rust_ty));
2493 }
2494 }
2495 }
2496 }
2497 None
2498 }
2499
2500 fn callee_param_is_bool(&self, func_name: &str, arg_index: usize) -> bool {
2502 if let Some(param_ut) = self.get_callee_param_type(func_name, arg_index) {
2504 return param_ut.is_bool();
2505 }
2506 if let Some(interned) = self.interner.lookup(func_name) {
2508 if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2509 let macro_arg_index = if self.perl_threaded
2512 && macro_info.is_thx_dependent
2513 && arg_index > 0
2514 {
2515 arg_index - 1
2516 } else {
2517 arg_index
2518 };
2519 if let Some(param) = macro_info.params.get(macro_arg_index) {
2520 if let Some(expr_ids) = macro_info.type_env.param_to_exprs.get(¶m.name) {
2522 for expr_id in expr_ids {
2523 if let Some(constraints) = macro_info.type_env.expr_constraints.get(expr_id) {
2524 for c in constraints {
2525 let rust_ty = c.ty.to_rust_string(self.interner);
2526 if rust_ty == "bool" {
2527 return true;
2528 }
2529 }
2530 }
2531 }
2532 }
2533 }
2534 }
2535 if let Some(dict) = self.inline_fn_dict {
2537 if let Some(func_def) = dict.get(interned) {
2538 for d in &func_def.declarator.derived {
2539 if let DerivedDecl::Function(param_list) = d {
2540 if let Some(param) = param_list.params.get(arg_index) {
2541 let has_bool = param.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2542 let has_pointer = param.declarator.as_ref().map_or(false, |decl| {
2543 decl.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)))
2544 });
2545 if has_bool && !has_pointer {
2546 return true;
2547 }
2548 }
2549 break;
2550 }
2551 }
2552 }
2553 }
2554 }
2555 false
2556 }
2557
2558 fn get_callee_return_type(&self, func_name: &str) -> Option<&UnifiedType> {
2560 self.rust_decl_dict?.fns.get(func_name).and_then(|f| {
2561 f.uret_ty.as_ref()
2562 })
2563 }
2564
2565 fn is_rust_enum_type(&self, ut: &UnifiedType) -> bool {
2569 if let UnifiedType::Named(name) = ut {
2570 if let Some(dict) = self.rust_decl_dict {
2571 return dict.enums.contains(name.as_str());
2572 }
2573 }
2574 false
2575 }
2576
2577 fn is_bool_expr_with_dict(&self, expr: &Expr) -> bool {
2579 if is_boolean_expr_recursive(expr, self.interner) {
2580 return true;
2581 }
2582 if let ExprKind::Index { expr: base, .. } = &expr.kind {
2584 if let ExprKind::Ident(name) = &base.kind {
2585 if let Some(dict) = self.rust_decl_dict {
2586 let name_str = self.interner.get(*name);
2587 if let Some(c) = dict.consts.get(name_str) {
2588 if let Some(inner) = c.uty.inner_type() {
2589 if inner.is_bool() {
2590 return true;
2591 }
2592 }
2593 }
2594 if dict.statics.contains(name_str) && name_str.starts_with("PL_valid_types_") {
2596 return true;
2597 }
2598 }
2599 }
2600 }
2601 if let ExprKind::Ident(name) = &expr.kind {
2603 if let Some(ut) = self.current_param_types.get(name) {
2604 if ut.is_bool() {
2605 return true;
2606 }
2607 }
2608 }
2609 if let ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } = &expr.kind {
2611 let member_str = self.interner.get(*member);
2612 if let Some(ut) = self.field_type_map.get(member_str) {
2613 if ut.is_bool() {
2614 return true;
2615 }
2616 }
2617 }
2618 if let ExprKind::Call { func, .. } = &expr.kind {
2620 if let ExprKind::Ident(name) = &func.kind {
2621 if self.bool_return_macros.contains(name) {
2623 return true;
2624 }
2625 let func_name = self.interner.get(*name);
2626 if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2628 return ret_ut.is_bool();
2629 }
2630 if let Some(macro_info) = self.macro_ctx.macros.get(name) {
2632 if let Some(ty) = macro_info.get_return_type() {
2633 let rust_ty = ty.to_rust_string(self.interner);
2634 return rust_ty == "bool";
2635 }
2636 }
2637 if let Some(dict) = self.inline_fn_dict {
2639 if let Some(func_def) = dict.get(*name) {
2640 let has_bool_return = func_def.specs.type_specs.iter().any(|ts| matches!(ts, TypeSpec::Bool));
2641 let has_return_pointer = func_def.declarator.derived.iter().any(|d| matches!(d, DerivedDecl::Pointer(_)));
2642 if has_bool_return && !has_return_pointer {
2643 return true;
2644 }
2645 }
2646 }
2647 }
2648 }
2649 if let ExprKind::MacroCall { name, .. } = &expr.kind {
2651 if self.bool_return_macros.contains(name) {
2652 return true;
2653 }
2654 }
2655 false
2656 }
2657
2658 fn find_literal_string_ident<'b>(&self, expr: &'b Expr) -> Option<&'b InternedStr> {
2661 match &expr.kind {
2662 ExprKind::Ident(name) if self.current_literal_string_params.contains(name) => {
2663 Some(name)
2664 }
2665 ExprKind::Call { func, args } if args.len() == 1 => {
2666 if let ExprKind::Ident(fname) = &func.kind {
2668 let func_name = self.interner.get(*fname);
2669 if func_name == "ASSERT_IS_LITERAL"
2670 || func_name == "ASSERT_IS_PTR"
2671 || func_name == "ASSERT_NOT_PTR"
2672 {
2673 return self.find_literal_string_ident(&args[0]);
2674 }
2675 }
2676 None
2677 }
2678 _ => None,
2679 }
2680 }
2681
2682
2683 fn should_emit_as_macro_call(&self, name: crate::InternedStr) -> bool {
2690 if let Some(info) = self.macro_ctx.macros.get(&name) {
2692 return info.is_parseable() && !info.calls_unavailable;
2694 }
2695 false
2696 }
2697
2698 fn unknown_marker(&mut self) -> &'static str {
2700 self.incomplete_count += 1;
2701 "/* unknown */"
2702 }
2703
2704 fn todo_marker(&mut self, msg: &str) -> String {
2706 self.incomplete_count += 1;
2707 format!("/* TODO: {} */", msg)
2708 }
2709
2710 fn type_marker(&mut self) -> &'static str {
2712 self.incomplete_count += 1;
2713 "/* type */"
2714 }
2715
2716 fn collect_decl_names(&mut self, decl: &Declaration) {
2719 let base_type = self.decl_specs_to_rust(&decl.specs);
2720 for init_decl in &decl.declarators {
2721 if let Some(name) = init_decl.declarator.name {
2722 self.current_local_names.insert(name);
2723 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2724 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2725 }
2726 }
2727 }
2728
2729 fn collect_local_names_recursive(&mut self, body: &CompoundStmt) {
2735 for item in &body.items {
2736 self.collect_local_names_from_block_item(item);
2737 }
2738 }
2739
2740 fn collect_local_names_from_block_item(&mut self, item: &BlockItem) {
2741 match item {
2742 BlockItem::Decl(d) => self.collect_decl_names(d),
2743 BlockItem::Stmt(s) => self.collect_local_names_from_stmt(s),
2744 }
2745 }
2746
2747 fn collect_local_names_from_stmt(&mut self, stmt: &Stmt) {
2748 match stmt {
2749 Stmt::Compound(c) => self.collect_local_names_recursive(c),
2750 Stmt::If { then_stmt, else_stmt, cond, .. } => {
2751 self.collect_local_names_from_expr(cond);
2752 self.collect_local_names_from_stmt(then_stmt);
2753 if let Some(es) = else_stmt {
2754 self.collect_local_names_from_stmt(es);
2755 }
2756 }
2757 Stmt::Switch { body, expr, .. } => {
2758 self.collect_local_names_from_expr(expr);
2759 self.collect_local_names_from_stmt(body);
2760 }
2761 Stmt::While { body, cond, .. } => {
2762 self.collect_local_names_from_expr(cond);
2763 self.collect_local_names_from_stmt(body);
2764 }
2765 Stmt::DoWhile { body, cond, .. } => {
2766 self.collect_local_names_from_stmt(body);
2767 self.collect_local_names_from_expr(cond);
2768 }
2769 Stmt::For { init, cond, step, body, .. } => {
2770 if let Some(i) = init {
2771 match i {
2772 ForInit::Decl(d) => self.collect_decl_names(d),
2773 ForInit::Expr(e) => self.collect_local_names_from_expr(e),
2774 }
2775 }
2776 if let Some(c) = cond { self.collect_local_names_from_expr(c); }
2777 if let Some(s) = step { self.collect_local_names_from_expr(s); }
2778 self.collect_local_names_from_stmt(body);
2779 }
2780 Stmt::Expr(Some(e), _) => self.collect_local_names_from_expr(e),
2781 Stmt::Return(Some(e), _) => self.collect_local_names_from_expr(e),
2782 Stmt::Label { stmt, .. } | Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => {
2783 self.collect_local_names_from_stmt(stmt);
2784 }
2785 _ => {}
2786 }
2787 }
2788
2789 fn collect_local_names_from_expr(&mut self, expr: &Expr) {
2790 if let ExprKind::StmtExpr(c) = &expr.kind {
2791 self.collect_local_names_recursive(c);
2792 }
2793 match &expr.kind {
2796 ExprKind::Binary { lhs, rhs, .. }
2797 | ExprKind::Assign { lhs, rhs, .. }
2798 | ExprKind::Comma { lhs, rhs } => {
2799 self.collect_local_names_from_expr(lhs);
2800 self.collect_local_names_from_expr(rhs);
2801 }
2802 ExprKind::Conditional { cond, then_expr, else_expr } => {
2803 self.collect_local_names_from_expr(cond);
2804 self.collect_local_names_from_expr(then_expr);
2805 self.collect_local_names_from_expr(else_expr);
2806 }
2807 ExprKind::Cast { expr: e, .. }
2808 | ExprKind::AddrOf(e) | ExprKind::Deref(e)
2809 | ExprKind::UnaryPlus(e) | ExprKind::UnaryMinus(e)
2810 | ExprKind::BitNot(e) | ExprKind::LogNot(e)
2811 | ExprKind::PreInc(e) | ExprKind::PreDec(e)
2812 | ExprKind::PostInc(e) | ExprKind::PostDec(e)
2813 | ExprKind::Sizeof(e)
2814 | ExprKind::Member { expr: e, .. } | ExprKind::PtrMember { expr: e, .. } => {
2815 self.collect_local_names_from_expr(e);
2816 }
2817 ExprKind::Call { func, args } => {
2818 self.collect_local_names_from_expr(func);
2819 for a in args { self.collect_local_names_from_expr(a); }
2820 }
2821 ExprKind::Index { expr: e, index } => {
2822 self.collect_local_names_from_expr(e);
2823 self.collect_local_names_from_expr(index);
2824 }
2825 _ => {}
2826 }
2827 }
2828
2829 fn collect_decl_types(&mut self, decl: &Declaration) {
2832 let base_type = self.decl_specs_to_rust(&decl.specs);
2833 for init_decl in &decl.declarators {
2834 if let Some(name) = init_decl.declarator.name {
2835 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
2836 self.current_param_types.insert(name, UnifiedType::from_rust_str(&ty));
2837 }
2838 }
2839 }
2840
2841 fn writeln(&mut self, s: &str) {
2843 self.buffer.push_str(s);
2844 self.buffer.push('\n');
2845 }
2846
2847 fn into_generated_code(self) -> GeneratedCode {
2849 GeneratedCode {
2850 code: self.buffer,
2851 incomplete_count: self.incomplete_count,
2852 unresolved_names: self.unresolved_names,
2853 used_libc_fns: self.used_libc_fns,
2854 codegen_errors: self.codegen_errors,
2855 }
2856 }
2857
2858 pub fn generate_macro(mut self, info: &MacroInferInfo) -> GeneratedCode {
2860 let name_str = self.interner.get(info.name);
2861
2862 for p in &info.params {
2864 self.current_local_names.insert(p.name);
2865 }
2866
2867 self.current_type_param_map = info.generic_type_params.iter()
2869 .filter(|(idx, _)| **idx >= 0)
2870 .filter_map(|(idx, generic_name)| {
2871 info.params.get(*idx as usize).map(|p| (p.name, generic_name.clone()))
2872 })
2873 .collect();
2874
2875 for (name, _) in &self.current_type_param_map {
2878 self.current_local_names.remove(name);
2879 }
2880
2881 self.current_literal_string_params = info.literal_string_params.iter()
2883 .filter_map(|&idx| info.params.get(idx).map(|p| p.name))
2884 .collect();
2885
2886 let generic_clause = self.build_generic_clause(info);
2888
2889 let params_with_types = self.build_param_list(info);
2892
2893 let return_type = self.get_return_type(info);
2895 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
2896
2897 if self.dump_types_for.as_deref() == Some(name_str) {
2899 self.dump_type_info(name_str, info, ¶ms_with_types, &return_type);
2900 }
2901
2902 let thx_param = if self.perl_threaded && info.is_thx_dependent {
2905 "my_perl: *mut PerlInterpreter"
2906 } else {
2907 ""
2908 };
2909
2910 let params_str = if thx_param.is_empty() {
2912 params_with_types.clone()
2913 } else if params_with_types.is_empty() {
2914 thx_param.to_string()
2915 } else {
2916 format!("{}, {}", thx_param, params_with_types)
2917 };
2918
2919 self.dump_ast_comment_for_expr(name_str, &info.parse_result);
2921
2922 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
2924 let generic_info = if !generic_clause.is_empty() { " [generic]" } else { "" };
2925 self.writeln(&format!("/// {}{}{} - macro function", name_str, thx_info, generic_info));
2926 self.writeln("#[inline]");
2927 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
2928
2929 self.writeln(&format!("pub unsafe fn {}{}({}) -> {} {{", name_str, generic_clause, params_str, return_type));
2931
2932 let needs_unsafe = info.has_unsafe_ops();
2934 let body_indent = if needs_unsafe { " " } else { " " };
2935
2936 if needs_unsafe {
2937 self.writeln(" unsafe {");
2938 }
2939
2940 match &info.parse_result {
2941 ParseResult::Expression(expr) => {
2942 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
2943 let mut syn_expr = self.build_syn_expr_with_type_hint(expr, Some(info), type_hint.as_deref());
2944
2945 if self.current_return_type.as_ref().is_some_and(|ut| ut.is_void()) {
2946 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2947 self.writeln(&format!("{}{};", body_indent, s));
2948 } else if self.current_return_type.as_ref().is_some_and(|ut| ut.is_bool())
2949 && !self.is_bool_expr_with_dict(expr)
2950 && !crate::syn_codegen::is_bool_syn_expr(&syn_expr) {
2951 if self.is_pointer_expr_unified(expr, Some(info))
2952 || self.infer_expr_type_unified(expr, Some(info)).is_some_and(|ut| ut.is_pointer()) {
2953 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2954 self.writeln(&format!("{}!({}).is_null()", body_indent, s));
2957 } else {
2958 syn_expr = crate::syn_codegen::wrap_as_bool(syn_expr);
2959 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2960 self.writeln(&format!("{}{}", body_indent, s));
2961 }
2962 } else {
2963 syn_expr = self.cast_return_syn_expr_if_needed(expr, Some(info), syn_expr);
2964 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr));
2965 self.writeln(&format!("{}{}", body_indent, s));
2966 }
2967 }
2968 ParseResult::Statement(block_items) => {
2969 for item in block_items {
2970 if let BlockItem::Stmt(stmt) = item {
2971 let rust_stmt = self.stmt_to_rust(stmt, info);
2972 if rust_stmt.is_empty() {
2973 continue; }
2975 self.writeln(&format!("{}{}", body_indent, rust_stmt));
2976 }
2977 }
2978 }
2979 ParseResult::Unparseable(_) => {
2980 self.writeln(&format!("{}unimplemented!()", body_indent));
2981 }
2982 }
2983
2984 if needs_unsafe {
2985 self.writeln(" }");
2986 }
2987
2988 self.writeln("}");
2989 self.writeln("");
2990
2991 self.into_generated_code()
2992 }
2993
2994 fn build_generic_clause(&self, info: &MacroInferInfo) -> String {
2996 if info.generic_type_params.is_empty() {
2997 return String::new();
2998 }
2999
3000 let mut params: Vec<&String> = info.generic_type_params.values().collect();
3002 params.sort();
3003 params.dedup();
3004
3005 format!("<{}>", params.iter().map(|s| s.as_str()).collect::<Vec<_>>().join(", "))
3006 }
3007
3008 fn build_param_list(&mut self, info: &MacroInferInfo) -> String {
3014 let usage = info.local_usage.clone().unwrap_or_else(|| {
3017 crate::local_usage::analyze_macro(&info.parse_result, &info.params)
3018 });
3019 let mut_params = usage.mut_names();
3020 self.mut_local_names = mut_params.clone();
3021 self.unused_param_names = info.params.iter()
3022 .map(|p| p.name)
3023 .filter(|n| usage.is_unused(*n))
3024 .collect();
3025 self.current_local_usage = Some(usage);
3026 let mut parts = Vec::new();
3027 for (i, p) in info.params.iter().enumerate() {
3028 if info.generic_type_params.contains_key(&(i as i32)) {
3029 continue;
3030 }
3031 let name = if self.unused_param_names.contains(&p.name) {
3034 format!("_{}", self.interner.get(p.name))
3035 } else {
3036 escape_rust_keyword(self.interner.get(p.name))
3037 };
3038 let ty = self.get_param_type(p, info, i);
3039 self.current_param_types.insert(p.name, UnifiedType::from_rust_str(&ty));
3041 let mut_prefix = if mut_params.contains(&p.name) { "mut " } else { "" };
3042 parts.push(format!("{}{}: {}", mut_prefix, name, ty));
3043 }
3044 parts.join(", ")
3045 }
3046
3047 fn get_param_type(&mut self, param: &MacroParam, info: &MacroInferInfo, param_index: usize) -> String {
3049 if let Some(generic_name) = info.generic_type_params.get(&(param_index as i32)) {
3051 return generic_name.clone();
3052 }
3053
3054 if info.literal_string_params.contains(¶m_index) {
3056 return "&str".to_string();
3057 }
3058
3059 let should_be_const = self.const_pointer_positions.contains(¶m_index);
3060
3061 if let Some(mut ty) = best_constraint_for_macro_param(info, param) {
3062 if should_be_const {
3063 ty.make_outer_pointer_const();
3064 } else if ty.has_outer_pointer() {
3065 ty.make_outer_pointer_mut();
3067 }
3068 return self.type_repr_to_rust(&ty);
3069 }
3070
3071 self.unknown_marker().to_string()
3072 }
3073
3074 fn get_return_type(&mut self, info: &MacroInferInfo) -> String {
3080 if let Some(generic_name) = info.generic_type_params.get(&-1) {
3082 return generic_name.clone();
3083 }
3084
3085 if self.is_bool_return {
3087 return "bool".to_string();
3088 }
3089
3090 match &info.parse_result {
3091 ParseResult::Expression(expr) => {
3092 if let Some(ty) = info.get_return_type() {
3093 let mut ty_str = self.type_repr_to_rust(ty);
3094 if ty_str != "()" {
3095 if ty_str.contains("*mut") {
3097 if let Some(expr_ut) = self.infer_expr_type(expr, info) {
3098 if expr_ut.is_const_pointer() {
3099 ty_str = ty_str.replace("*mut", "*const");
3100 }
3101 }
3102 }
3103 return ty_str;
3104 }
3105 if let Some(ut) = self.infer_expr_type(expr, info) {
3109 let s = ut.to_rust_string();
3110 if s != "()" {
3111 return s;
3112 }
3113 }
3114 return ty_str;
3116 }
3117 self.unknown_marker().to_string()
3118 }
3119 ParseResult::Statement(_) => "()".to_string(),
3120 ParseResult::Unparseable(_) => "()".to_string(),
3121 }
3122 }
3123
3124 fn type_repr_to_rust(&mut self, ty: &crate::type_repr::TypeRepr) -> String {
3128 let result = ty.to_rust_string(self.interner);
3129 let result = self.substitute_type_params(&result);
3130 if result.contains("/*") {
3131 self.incomplete_count += 1;
3132 }
3133 result
3134 }
3135
3136 fn substitute_type_params(&self, type_str: &str) -> String {
3138 if self.current_type_param_map.is_empty() {
3139 return type_str.to_string();
3140 }
3141 let mut result = type_str.to_string();
3142 for (param_name, generic_name) in &self.current_type_param_map {
3143 let name_str = self.interner.get(*param_name);
3144 result = replace_word(&result, name_str, generic_name);
3146 }
3147 result
3148 }
3149
3150 fn detect_mutable_ptr_pattern<'b>(&self, compound: &'b CompoundStmt) -> Option<&'b Expr> {
3155 if compound.items.len() != 2 {
3157 return None;
3158 }
3159
3160 let decl = match &compound.items[0] {
3162 BlockItem::Decl(d) => d,
3163 _ => return None,
3164 };
3165
3166 if decl.declarators.len() != 1 {
3168 return None;
3169 }
3170 let init_decl = &decl.declarators[0];
3171 let declared_name = init_decl.declarator.name?;
3172 let init = init_decl.init.as_ref()?;
3173
3174 let init_expr = match init {
3176 Initializer::Expr(e) => e.as_ref(),
3177 _ => return None,
3178 };
3179
3180 let last_expr = match &compound.items[1] {
3182 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => e,
3183 _ => return None,
3184 };
3185
3186 if let ExprKind::Ident(name) = &last_expr.kind {
3188 if *name == declared_name {
3189 return Some(init_expr);
3190 }
3191 }
3192
3193 None
3194 }
3195
3196 fn maybe_decay_flex_array(
3207 &self,
3208 access: syn::Expr,
3209 base: &Expr,
3210 member: InternedStr,
3211 info: Option<&MacroInferInfo>,
3212 is_ptr_member: bool,
3213 ) -> syn::Expr {
3214 let Some(fd) = self.fields_dict else { return access; };
3215 let Some(info) = info else { return access; };
3216 let Some(constraints) = info.type_env.expr_constraints.get(&base.id) else {
3217 return access;
3218 };
3219 let Some(base_type) = constraints.first().map(|c| &c.ty) else {
3220 return access;
3221 };
3222 let struct_name = if is_ptr_member {
3223 base_type.pointee_name()
3224 } else {
3225 base_type.type_name()
3226 };
3227 let Some(struct_name) = struct_name else { return access; };
3228 let Some(elem) = fd.flexible_array_element(struct_name, member) else {
3229 return access;
3230 };
3231 let elem_str = elem.to_rust_string(self.interner);
3233 let target_ty_str = format!("*mut {}", elem_str);
3234 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3235 attrs: vec![],
3236 and_token: Default::default(),
3237 raw: Default::default(),
3238 mutability: syn::PointerMutability::Const(Default::default()),
3239 expr: Box::new(access),
3240 });
3241 crate::syn_codegen::insert_cast(raw_const, crate::syn_codegen::parse_type(&target_ty_str))
3242 }
3243
3244 fn try_inline_call_for_addrof(&self, inner: &Expr) -> Option<Expr> {
3253 let (callee_id, args) = match &inner.kind {
3254 ExprKind::Call { func, args } => match &func.kind {
3255 ExprKind::Ident(name) => (*name, args),
3256 _ => return None,
3257 },
3258 _ => return None,
3259 };
3260
3261 let callee_info = self.macro_ctx.macros.get(&callee_id)?;
3262 let body = match &callee_info.parse_result {
3263 ParseResult::Expression(e) => e,
3264 _ => return None,
3265 };
3266
3267 if callee_info.is_thx_dependent {
3269 return None;
3270 }
3271 if callee_info.params.len() != args.len() {
3272 return None;
3273 }
3274
3275 let mut subs: HashMap<InternedStr, &Expr> = HashMap::new();
3277 for (param, arg) in callee_info.params.iter().zip(args.iter()) {
3278 subs.insert(param.name, arg);
3279 }
3280
3281 let mut inlined = (**body).clone();
3282 substitute_idents(&mut inlined, &subs);
3283 Some(inlined)
3284 }
3285
3286 fn build_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
3291 use crate::syn_codegen::*;
3292
3293 match &expr.kind {
3294 ExprKind::Ident(name) => {
3295 if let Some(subst) = self.param_substitutions.get(name) {
3297 return syn::parse_str(subst).unwrap_or_else(|_| int_lit(0));
3299 }
3300 let name_str = self.interner.get(*name);
3301 if LIBC_FUNCTIONS.contains(&name_str) {
3303 self.used_libc_fns.insert(name_str.to_string());
3304 }
3305 if !self.current_local_names.contains(name)
3307 && !self.enum_dict.is_enum_variant(*name)
3308 && !self.known_symbols.contains(name_str)
3309 {
3310 let s = name_str.to_string();
3311 if !self.unresolved_names.contains(&s) {
3312 self.unresolved_names.push(s);
3313 }
3314 }
3315 if name_str == "true" || name_str == "false" {
3317 return syn::Expr::Lit(syn::ExprLit {
3318 attrs: vec![],
3319 lit: syn::Lit::Bool(syn::LitBool {
3320 value: name_str == "true",
3321 span: proc_macro2::Span::call_site(),
3322 }),
3323 });
3324 }
3325 let escaped = escape_rust_keyword(name_str);
3326 if self.bindings_info.static_arrays.contains(name_str) {
3341 let elem = self.bindings_info.static_array_element_type(name_str)
3342 .unwrap_or_else(|| "u8".to_string());
3343 return syn::parse_str(&format!(
3344 "((&raw const {}) as *const {})",
3345 escaped, elem
3346 ))
3347 .unwrap_or_else(|_| int_lit(0));
3348 }
3349 syn::Expr::Path(syn::ExprPath {
3350 attrs: vec![],
3351 qself: None,
3352 path: ident(&escaped).into(),
3353 })
3354 }
3355 ExprKind::IntLit(n) => int_lit(*n),
3356 ExprKind::UIntLit(n) => {
3357 let lit = syn::LitInt::new(&format!("{}u64", n), proc_macro2::Span::call_site());
3358 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Int(lit) })
3359 }
3360 ExprKind::FloatLit(f) => {
3361 let lit = syn::LitFloat::new(&format!("{}", f), proc_macro2::Span::call_site());
3362 syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Float(lit) })
3363 }
3364 ExprKind::CharLit(c) => {
3365 let s = if c.is_ascii() {
3366 format!("b'{}' as i8", escape_char(*c))
3367 } else {
3368 format!("0x{:02x}u8 as i8", c)
3369 };
3370 syn::parse_str(&s).unwrap_or_else(|_| int_lit(0))
3371 }
3372 ExprKind::StringLit(s) => {
3373 syn::parse_str(&format!("c\"{}\"", escape_string(s)))
3374 .unwrap_or_else(|_| int_lit(0))
3375 }
3376 ExprKind::Deref(inner) => {
3377 let e = self.build_syn_expr(inner, info);
3378 deref(e)
3379 }
3380 ExprKind::AddrOf(inner) => {
3381 if let Some(inlined) = self.try_inline_call_for_addrof(inner) {
3387 let e = self.build_syn_expr(&inlined, info);
3388 return addr_of_mut(e);
3389 }
3390 let e = self.build_syn_expr(inner, info);
3391 addr_of_mut(e)
3392 }
3393 ExprKind::UnaryPlus(inner) => {
3394 self.build_syn_expr(inner, info)
3395 }
3396 ExprKind::BitNot(inner) => {
3397 let e = self.build_syn_expr(inner, info);
3398 syn::Expr::Unary(syn::ExprUnary {
3399 attrs: vec![],
3400 op: syn::UnOp::Not(Default::default()),
3401 expr: Box::new(e),
3402 })
3403 }
3404 ExprKind::Member { expr: base, member } => {
3405 let e = self.build_syn_expr(base, info);
3406 let m = self.interner.get(*member);
3407 if self.is_bitfield_method(m) {
3408 syn::Expr::MethodCall(syn::ExprMethodCall {
3410 attrs: vec![],
3411 receiver: Box::new(e),
3412 dot_token: Default::default(),
3413 method: ident(m),
3414 turbofish: None,
3415 paren_token: Default::default(),
3416 args: syn::punctuated::Punctuated::new(),
3417 })
3418 } else {
3419 let access = field_access(e, m);
3420 self.maybe_decay_flex_array(access, base, *member, info, false)
3421 }
3422 }
3423 ExprKind::PtrMember { expr: base, member } => {
3424 let e = self.build_syn_expr(base, info);
3425 let m = self.interner.get(*member);
3426 let derefed = deref(e);
3427 if self.is_bitfield_method(m) {
3428 syn::Expr::MethodCall(syn::ExprMethodCall {
3429 attrs: vec![],
3430 receiver: Box::new(derefed),
3431 dot_token: Default::default(),
3432 method: ident(m),
3433 turbofish: None,
3434 paren_token: Default::default(),
3435 args: syn::punctuated::Punctuated::new(),
3436 })
3437 } else {
3438 let access = field_access(derefed, m);
3439 self.maybe_decay_flex_array(access, base, *member, info, true)
3440 }
3441 }
3442 ExprKind::Comma { lhs, rhs } => {
3443 let l = self.build_syn_expr(lhs, info);
3444 let r = self.build_syn_expr(rhs, info);
3445 if expr_yields_value_for_stmt_use(&l) {
3457 let l_str = expr_to_string(&l);
3458 let r_str = expr_to_string(&r);
3459 syn::parse_str(&format!("{{ let _ = {}; {} }}", l_str, r_str))
3460 .unwrap_or_else(|_| int_lit(0))
3461 } else {
3462 syn::Expr::Block(syn::ExprBlock {
3463 attrs: vec![],
3464 label: None,
3465 block: syn::Block {
3466 brace_token: Default::default(),
3467 stmts: vec![
3468 syn::Stmt::Expr(l, Some(Default::default())),
3469 syn::Stmt::Expr(r, None),
3470 ],
3471 },
3472 })
3473 }
3474 }
3475 ExprKind::UnaryMinus(inner) => {
3476 let e = self.build_syn_expr(inner, info);
3477 let e_str = expr_to_string(&e);
3479 if is_unsigned_cast_expr(&e_str) {
3480 return syn::parse_str(&format!("({}).wrapping_neg()", e_str.trim_start_matches('-')))
3481 .unwrap_or_else(|_| int_lit(0));
3482 }
3483 if let Some(ut) = self.infer_expr_type_unified(inner, info) {
3484 let ts = ut.to_rust_string();
3485 if matches!(normalize_integer_type(&ts), Some("usize" | "u8" | "u16" | "u32" | "u64")) {
3486 self.codegen_errors.push(format!("cannot negate unsigned type: -({}: {})", e_str, ts));
3487 }
3488 }
3489 syn::Expr::Unary(syn::ExprUnary {
3490 attrs: vec![],
3491 op: syn::UnOp::Neg(Default::default()),
3492 expr: Box::new(e),
3493 })
3494 }
3495 ExprKind::LogNot(inner) => {
3496 if matches!(&inner.kind, ExprKind::StringLit(_)) {
3498 return syn::parse_str("false").unwrap_or_else(|_| int_lit(0));
3499 }
3500 let e = self.build_syn_expr(inner, info);
3501 if !self.is_bool_expr_with_dict(inner)
3502 && (self.is_pointer_expr_unified(inner, info)
3503 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()))
3504 {
3505 return syn::Expr::MethodCall(syn::ExprMethodCall {
3510 attrs: vec![],
3511 receiver: Box::new(e),
3512 dot_token: Default::default(),
3513 method: ident("is_null"),
3514 turbofish: None,
3515 paren_token: Default::default(),
3516 args: syn::punctuated::Punctuated::new(),
3517 });
3518 }
3519 let bool_e = if self.is_bool_expr_with_dict(inner) {
3520 e
3521 } else {
3522 wrap_as_bool(e)
3524 };
3525 syn::Expr::Unary(syn::ExprUnary {
3526 attrs: vec![],
3527 op: syn::UnOp::Not(Default::default()),
3528 expr: Box::new(bool_e),
3529 })
3530 }
3531 ExprKind::Cast { type_name, expr: inner } => {
3532 let t = self.type_name_to_rust(type_name);
3533 if is_unsigned_integer_target(&t) {
3537 if let ExprKind::UnaryMinus(minus_inner) = &inner.kind {
3538 if matches!(&minus_inner.kind,
3539 ExprKind::IntLit(1) | ExprKind::UIntLit(1))
3540 {
3541 return syn::parse_str(&format!("{}::MAX", t))
3542 .unwrap_or_else(|_| int_lit(0));
3543 }
3544 }
3545 }
3546 if (t.starts_with("*mut ") || t.starts_with("*const "))
3553 && matches!(&inner.kind, ExprKind::AddrOf(_))
3554 {
3555 if let ExprKind::AddrOf(addrof_inner) = &inner.kind {
3556 let inlined_owned;
3558 let inner_to_build: &Expr =
3559 if let Some(inlined) = self.try_inline_call_for_addrof(addrof_inner) {
3560 inlined_owned = inlined;
3561 &inlined_owned
3562 } else {
3563 addrof_inner
3564 };
3565 let inner_e = self.build_syn_expr(inner_to_build, info);
3566 let raw_const = syn::Expr::RawAddr(syn::ExprRawAddr {
3567 attrs: vec![],
3568 and_token: Default::default(),
3569 raw: Default::default(),
3570 mutability: syn::PointerMutability::Const(Default::default()),
3571 expr: Box::new(inner_e),
3572 });
3573 return insert_cast(raw_const, parse_type(&t));
3574 }
3575 }
3576 let e = self.build_syn_expr(inner, info);
3577 if t == "()" {
3578 let e_str = expr_to_string(&e);
3585 return syn::parse_str(&format!("{{ let _ = {}; }}", e_str))
3586 .unwrap_or_else(|_| int_lit(0));
3587 }
3588 if t == "bool" {
3589 if self.is_bool_expr_with_dict(inner) {
3591 return e;
3592 }
3593 if self.is_pointer_expr_unified(inner, info)
3594 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer()) {
3595 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3597 attrs: vec![],
3598 receiver: Box::new(e),
3599 dot_token: Default::default(),
3600 method: ident("is_null"),
3601 turbofish: None,
3602 paren_token: Default::default(),
3603 args: syn::punctuated::Punctuated::new(),
3604 });
3605 return syn::Expr::Unary(syn::ExprUnary {
3606 attrs: vec![],
3607 op: syn::UnOp::Not(Default::default()),
3608 expr: Box::new(is_null),
3609 });
3610 }
3611 return wrap_as_bool(e);
3612 }
3613 if self.is_enum_cast_target(type_name) {
3614 let e_str = expr_to_string(&e);
3616 return syn::parse_str(&format!("std::mem::transmute::<_, {}>({})", t, e_str))
3617 .unwrap_or_else(|_| int_lit(0));
3618 }
3619 insert_cast(e, parse_type(&t))
3620 }
3621 ExprKind::Sizeof(inner) => {
3622 if let ExprKind::Ident(name) = &inner.kind {
3624 if self.current_literal_string_params.contains(name) {
3625 let param = escape_rust_keyword(self.interner.get(*name));
3626 return syn::parse_str(&format!("({}.len() + 1)", param))
3627 .unwrap_or_else(|_| int_lit(0));
3628 }
3629 }
3630 let e = self.build_syn_expr(inner, info);
3631 let e_str = expr_to_string(&e);
3632 syn::parse_str(&format!("std::mem::size_of_val(&({}))", e_str))
3637 .unwrap_or_else(|_| int_lit(0))
3638 }
3639 ExprKind::SizeofType(type_name) => {
3640 let t = self.type_name_to_rust(type_name);
3641 syn::parse_str(&format!("std::mem::size_of::<{}>()", t))
3642 .unwrap_or_else(|_| int_lit(0))
3643 }
3644 ExprKind::Index { expr: base, index } => {
3645 use crate::syn_codegen::*;
3646 let i = self.build_syn_expr(index, info);
3647 let i_isize = cast_syn_expr(i, "isize");
3648 let base_expr: syn::Expr = if self.is_array_like_expr(base, info) {
3649 let raw_ptr_expr: syn::Expr = if let ExprKind::Ident(n) = &base.kind {
3655 let name_str = self.interner.get(*n);
3656 let escaped = escape_rust_keyword(name_str);
3657 if self.bindings_info.static_arrays.contains(name_str) {
3658 let elem = self.bindings_info
3659 .static_array_element_type(name_str)
3660 .unwrap_or_else(|| "u8".to_string());
3661 syn::parse_str(&format!(
3662 "((&raw const {}) as *const {})",
3663 escaped, elem
3664 ))
3665 .unwrap_or_else(|_| int_lit(0))
3666 } else {
3667 let id = ident_expr(escaped.as_str());
3668 method_call(id, "as_ptr", vec![])
3669 }
3670 } else {
3671 let b = self.build_syn_expr(base, info);
3672 method_call(b, "as_ptr", vec![])
3673 };
3674 let elem_str = self.infer_expr_type_unified(base, info)
3678 .and_then(|ut| ut.inner_type().cloned())
3679 .map(|inner| inner.to_rust_string());
3680 if let Some(elem) = elem_str {
3681 cast_syn_expr(raw_ptr_expr, &format!("*mut {}", elem))
3682 } else {
3683 raw_ptr_expr
3684 }
3685 } else {
3686 self.build_syn_expr(base, info)
3687 };
3688 let offset_call = method_call(base_expr, "offset", vec![i_isize]);
3689 deref(offset_call)
3690 }
3691 ExprKind::Conditional { cond, then_expr, else_expr } => {
3692 let c = self.build_syn_expr(cond, info);
3693 let c_str = expr_to_string(&c);
3694 let cond_str = self.wrap_as_bool_condition(cond, &c_str, info);
3695 let cond_syn: syn::Expr = syn::parse_str(&cond_str).unwrap_or(c);
3696
3697 let type_hint = self.current_return_type.as_ref().map(|ut| ut.to_rust_string());
3698 let tt = self.infer_expr_type_unified(then_expr, info);
3699 let et = self.infer_expr_type_unified(else_expr, info);
3700
3701 if let Some(ref hint) = type_hint {
3703 let hint_ut = UnifiedType::from_rust_str(hint);
3704 if hint_ut.is_pointer() {
3705 if is_null_literal(else_expr)
3712 && tt.as_ref().map_or(true, |t| t.is_pointer())
3713 {
3714 let t = self.build_syn_expr(then_expr, info);
3715 let e: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3716 .unwrap_or_else(|_| int_lit(0));
3717 return if_else(cond_syn, t, e);
3718 }
3719 if is_null_literal(then_expr)
3720 && et.as_ref().map_or(true, |t| t.is_pointer())
3721 {
3722 let t: syn::Expr = syn::parse_str(&null_ptr_expr(&hint_ut))
3723 .unwrap_or_else(|_| int_lit(0));
3724 let e = self.build_syn_expr(else_expr, info);
3725 return if_else(cond_syn, t, e);
3726 }
3727 }
3728 if normalize_integer_type(hint).is_some() {
3731 if is_null_literal(else_expr) {
3732 let t = self.build_syn_expr(then_expr, info);
3733 return if_else(cond_syn, t, int_lit(0));
3734 }
3735 if is_null_literal(then_expr) {
3736 let e = self.build_syn_expr(else_expr, info);
3737 return if_else(cond_syn, int_lit(0), e);
3738 }
3739 }
3740 if hint_ut.is_bool() {
3741 let then_syn = match &then_expr.kind {
3742 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3743 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3744 _ => self.build_syn_expr(then_expr, info),
3745 };
3746 let else_syn = match &else_expr.kind {
3747 ExprKind::IntLit(0) => syn::parse_str("false").unwrap(),
3748 ExprKind::IntLit(1) => syn::parse_str("true").unwrap(),
3749 _ => self.build_syn_expr(else_expr, info),
3750 };
3751 return if_else(cond_syn, then_syn, else_syn);
3752 }
3753 }
3754
3755 let then_syn = if is_null_literal(then_expr) {
3757 if let Some(ref eut) = et {
3758 if eut.is_pointer() {
3759 syn::parse_str(&null_ptr_expr(eut)).unwrap_or_else(|_| int_lit(0))
3760 } else { self.build_syn_expr(then_expr, info) }
3761 } else { self.build_syn_expr(then_expr, info) }
3762 } else { self.build_syn_expr(then_expr, info) };
3763
3764 let else_syn = if is_null_literal(else_expr) {
3765 if let Some(ref tut) = tt {
3766 if tut.is_pointer() {
3767 syn::parse_str(&null_ptr_expr(tut)).unwrap_or_else(|_| int_lit(0))
3768 } else { self.build_syn_expr(else_expr, info) }
3769 } else { self.build_syn_expr(else_expr, info) }
3770 } else { self.build_syn_expr(else_expr, info) };
3771
3772 if let (Some(tut), Some(eut)) = (&tt, &et) {
3774 let ts = tut.to_rust_string();
3775 let es = eut.to_rust_string();
3776 if let (Some(tn), Some(en)) = (normalize_integer_type(&ts), normalize_integer_type(&es)) {
3777 if tn != en {
3778 if let Some(wider) = wider_integer_type(&ts, &es) {
3779 let (then_final, else_final) = if normalize_integer_type(&ts) != Some(wider) {
3780 (cast_syn_expr(then_syn, wider), else_syn)
3781 } else {
3782 (then_syn, cast_syn_expr(else_syn, wider))
3783 };
3784 return if_else(cond_syn, then_final, else_final);
3785 }
3786 }
3787 }
3788 if tut.is_pointer() && eut.is_pointer() && ts != es
3791 && is_sv_subtype_cast(tut, eut)
3792 {
3793 let target_str = type_hint.as_deref()
3796 .filter(|t| *t != "()" && !UnifiedType::from_rust_str(t).is_void())
3797 .unwrap_or(&ts)
3798 .to_string();
3799 return if_else(
3800 cond_syn,
3801 cast_syn_expr(then_syn, &target_str),
3802 cast_syn_expr(else_syn, &target_str),
3803 );
3804 }
3805 }
3806
3807 if_else(cond_syn, then_syn, else_syn)
3808 }
3809 ExprKind::Binary { op, lhs, rhs } => {
3810 if *op == BinOp::Sub {
3812 if let ExprKind::Sizeof(inner) = &lhs.kind {
3813 if let ExprKind::Ident(name) = &inner.kind {
3814 if self.current_literal_string_params.contains(name) {
3815 if let ExprKind::IntLit(1) = &rhs.kind {
3816 let param = escape_rust_keyword(self.interner.get(*name));
3817 return syn::parse_str(&format!("{}.len()", param))
3818 .unwrap_or_else(|_| int_lit(0));
3819 }
3820 }
3821 }
3822 }
3823 }
3824
3825 if matches!(op, BinOp::Eq | BinOp::Ne) {
3828 let s_eq = |s: &ExprKind| matches!(s, ExprKind::StringLit(_));
3829 let lhs_is_str = s_eq(&lhs.kind);
3830 let rhs_is_str = s_eq(&rhs.kind);
3831 if (lhs_is_str && is_null_literal(rhs))
3832 || (rhs_is_str && is_null_literal(lhs))
3833 {
3834 return syn::parse_str(
3835 if *op == BinOp::Eq { "false" } else { "true" }
3836 ).unwrap_or_else(|_| int_lit(0));
3837 }
3838 }
3839 if matches!(op, BinOp::Eq | BinOp::Ne) {
3843 let opt_lhs = (is_null_literal(rhs) || matches!(&rhs.kind, ExprKind::IntLit(0)))
3844 && self.is_option_fn_pointer_expr(lhs, info);
3845 let opt_rhs = (is_null_literal(lhs) || matches!(&lhs.kind, ExprKind::IntLit(0)))
3846 && self.is_option_fn_pointer_expr(rhs, info);
3847 if opt_lhs || opt_rhs {
3848 let receiver_expr = if opt_lhs { lhs } else { rhs };
3849 let r = self.build_syn_expr(receiver_expr, info);
3850 let method = if *op == BinOp::Eq { "is_none" } else { "is_some" };
3851 return syn::Expr::MethodCall(syn::ExprMethodCall {
3852 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3853 method: ident(method), turbofish: None,
3854 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3855 });
3856 }
3857 }
3858 if matches!(op, BinOp::Eq | BinOp::Ne) {
3860 if is_null_literal(rhs) {
3861 if self.is_pointer_expr_unified(lhs, info)
3862 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer()) {
3863 let l = self.build_syn_expr(lhs, info);
3864 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3865 attrs: vec![], receiver: Box::new(l), dot_token: Default::default(),
3866 method: ident("is_null"), turbofish: None,
3867 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3868 });
3869 return if *op == BinOp::Eq { is_null } else {
3870 syn::Expr::Unary(syn::ExprUnary {
3871 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3872 expr: Box::new(is_null),
3873 })
3874 };
3875 }
3876 }
3877 if is_null_literal(lhs) {
3878 if self.is_pointer_expr_unified(rhs, info)
3879 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer()) {
3880 let r = self.build_syn_expr(rhs, info);
3881 let is_null = syn::Expr::MethodCall(syn::ExprMethodCall {
3882 attrs: vec![], receiver: Box::new(r), dot_token: Default::default(),
3883 method: ident("is_null"), turbofish: None,
3884 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
3885 });
3886 return if *op == BinOp::Eq { is_null } else {
3887 syn::Expr::Unary(syn::ExprUnary {
3888 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3889 expr: Box::new(is_null),
3890 })
3891 };
3892 }
3893 }
3894 if self.is_bool_expr_with_dict(lhs) {
3896 match (&rhs.kind, op) {
3897 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
3898 return self.build_syn_expr(lhs, info);
3899 }
3900 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
3901 let l = self.build_syn_expr(lhs, info);
3902 return syn::Expr::Unary(syn::ExprUnary {
3903 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3904 expr: Box::new(l),
3905 });
3906 }
3907 _ => {}
3908 }
3909 }
3910 if self.is_bool_expr_with_dict(rhs) {
3911 match (&lhs.kind, op) {
3912 (ExprKind::IntLit(0), BinOp::Ne) | (ExprKind::IntLit(1), BinOp::Eq) => {
3913 return self.build_syn_expr(rhs, info);
3914 }
3915 (ExprKind::IntLit(0), BinOp::Eq) | (ExprKind::IntLit(1), BinOp::Ne) => {
3916 let r = self.build_syn_expr(rhs, info);
3917 return syn::Expr::Unary(syn::ExprUnary {
3918 attrs: vec![], op: syn::UnOp::Not(Default::default()),
3919 expr: Box::new(r),
3920 });
3921 }
3922 _ => {}
3923 }
3924 }
3925 }
3926
3927 if matches!(op, BinOp::Add | BinOp::Sub) {
3929 let l_arr = !self.is_static_array_expr(lhs)
3934 && self.is_array_like_expr(lhs, info);
3935 let r_arr = !self.is_static_array_expr(rhs)
3936 && self.is_array_like_expr(rhs, info);
3937 let lp = l_arr
3938 || self.is_static_array_expr(lhs)
3939 || self.is_pointer_expr_unified(lhs, info)
3940 || self.infer_expr_type_unified(lhs, info).is_some_and(|ut| ut.is_pointer());
3941 let rp = r_arr
3942 || self.is_static_array_expr(rhs)
3943 || self.is_pointer_expr_unified(rhs, info)
3944 || self.infer_expr_type_unified(rhs, info).is_some_and(|ut| ut.is_pointer());
3945 let l_is_static_arr = self.is_static_array_expr(lhs);
3952 let r_is_static_arr = self.is_static_array_expr(rhs);
3953 let cast_to_mut = |this: &mut Self, expr: syn::Expr, arr_expr: &Expr,
3954 needs_as_ptr: bool| -> syn::Expr {
3955 let elem = this.infer_expr_type_unified(arr_expr, info)
3956 .and_then(|ut| ut.inner_type().cloned())
3957 .map(|u| u.to_rust_string());
3958 let base = if needs_as_ptr {
3959 crate::syn_codegen::method_call(expr, "as_ptr", vec![])
3960 } else {
3961 expr
3962 };
3963 if let Some(e) = elem {
3964 crate::syn_codegen::cast_syn_expr(base, &format!("*mut {}", e))
3965 } else {
3966 base
3967 }
3968 };
3969 if lp && !rp {
3970 let l = self.build_syn_expr(lhs, info);
3971 let l = if l_arr {
3972 cast_to_mut(self, l, lhs, true)
3973 } else if l_is_static_arr {
3974 cast_to_mut(self, l, lhs, false)
3975 } else {
3976 l
3977 };
3978 let r = self.build_syn_expr(rhs, info);
3979 let r_isize = crate::syn_codegen::cast_syn_expr(r, "isize");
3980 let arg = if *op == BinOp::Add { r_isize } else {
3981 syn::Expr::Unary(syn::ExprUnary {
3982 attrs: vec![],
3983 op: syn::UnOp::Neg(Default::default()),
3984 expr: Box::new(r_isize),
3985 })
3986 };
3987 return crate::syn_codegen::method_call(l, "offset", vec![arg]);
3988 }
3989 if rp && !lp && *op == BinOp::Add {
3990 let l = self.build_syn_expr(lhs, info);
3991 let r = self.build_syn_expr(rhs, info);
3992 let r = if r_arr {
3993 cast_to_mut(self, r, rhs, true)
3994 } else if r_is_static_arr {
3995 cast_to_mut(self, r, rhs, false)
3996 } else {
3997 r
3998 };
3999 let l_isize = crate::syn_codegen::cast_syn_expr(l, "isize");
4000 return crate::syn_codegen::method_call(r, "offset", vec![l_isize]);
4001 }
4002 if lp && rp && *op == BinOp::Sub {
4003 let l = self.build_syn_expr(lhs, info);
4004 let r = self.build_syn_expr(rhs, info);
4005 return crate::syn_codegen::method_call(l, "offset_from", vec![r]);
4006 }
4007 }
4008
4009 if matches!(&rhs.kind, ExprKind::IntLit(_)) {
4011 if let Some(lut) = self.infer_expr_type_unified(lhs, info) {
4012 if lut.is_float() {
4013 if let ExprKind::IntLit(v) = &rhs.kind {
4014 let l = self.build_syn_expr(lhs, info);
4015 let l_str = expr_to_string(&l);
4016 return syn::parse_str(&format!("{} {} {}.0", l_str, bin_op_to_rust(*op), v))
4017 .unwrap_or_else(|_| int_lit(0));
4018 }
4019 }
4020 }
4021 }
4022 if matches!(&lhs.kind, ExprKind::IntLit(_)) {
4023 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4024 if rut.is_float() {
4025 if let ExprKind::IntLit(v) = &lhs.kind {
4026 let r = self.build_syn_expr(rhs, info);
4027 let r_str = expr_to_string(&r);
4028 return syn::parse_str(&format!("{}.0 {} {}", v, bin_op_to_rust(*op), r_str))
4029 .unwrap_or_else(|_| int_lit(0));
4030 }
4031 }
4032 }
4033 }
4034
4035 if matches!(op, BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Eq | BinOp::Ne) {
4040 if let (Some(lut), Some(rut)) =
4041 (self.infer_expr_type_unified(lhs, info),
4042 self.infer_expr_type_unified(rhs, info))
4043 {
4044 if lut.is_pointer() && rut.is_pointer()
4045 && pointer_inner_compatible(&lut, &rut)
4046 && (lut.is_const_pointer() != rut.is_const_pointer()
4047 || lut.to_rust_string() != rut.to_rust_string())
4048 {
4049 let l = self.build_syn_expr(lhs, info);
4050 let r = self.build_syn_expr(rhs, info);
4051 let target = lut.to_rust_string();
4052 return syn::Expr::Binary(syn::ExprBinary {
4053 attrs: vec![], left: Box::new(l),
4054 op: crate::syn_codegen::to_syn_binop(*op),
4055 right: Box::new(crate::syn_codegen::cast_syn_expr(r, &target)),
4056 });
4057 }
4058 }
4059 }
4060
4061 let l = self.build_syn_expr(lhs, info);
4062 let r = self.build_syn_expr(rhs, info);
4063
4064 if matches!(op, BinOp::LogAnd | BinOp::LogOr) {
4066 let l_str = expr_to_string(&l);
4067 let r_str = expr_to_string(&r);
4068 let l_bool = self.wrap_as_bool_condition(lhs, &l_str, info);
4069 let r_bool = self.wrap_as_bool_condition(rhs, &r_str, info);
4070 let l_syn: syn::Expr = syn::parse_str(&l_bool).unwrap_or(l);
4071 let r_syn: syn::Expr = syn::parse_str(&r_bool).unwrap_or(r);
4072 return syn::Expr::Binary(syn::ExprBinary {
4073 attrs: vec![], left: Box::new(l_syn),
4074 op: crate::syn_codegen::to_syn_binop(*op),
4075 right: Box::new(r_syn),
4076 });
4077 }
4078
4079 let lt = self.infer_expr_type_unified(lhs, info);
4081 let rt = self.infer_expr_type_unified(rhs, info);
4082
4083 let make_binary_op = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4087 syn::Expr::Binary(syn::ExprBinary {
4088 attrs: vec![], left: Box::new(left),
4089 op: crate::syn_codegen::to_syn_binop(*op),
4090 right: Box::new(right),
4091 })
4092 };
4093 match (<, &rt) {
4094 (Some(lut), None) if self.is_rust_enum_type(lut) => {
4095 return make_binary_op(cast_syn_expr(l, "u32"), r);
4096 }
4097 (None, Some(rut)) if self.is_rust_enum_type(rut) => {
4098 return make_binary_op(l, cast_syn_expr(r, "u32"));
4099 }
4100 _ => {}
4101 }
4102
4103 if let (Some(lut), Some(rut)) = (<, &rt) {
4104 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4105 syn::Expr::Binary(syn::ExprBinary {
4106 attrs: vec![], left: Box::new(left),
4107 op: crate::syn_codegen::to_syn_binop(*op),
4108 right: Box::new(right),
4109 })
4110 };
4111 let l_is_enum = self.is_rust_enum_type(lut);
4114 let r_is_enum = self.is_rust_enum_type(rut);
4115 if l_is_enum && !r_is_enum {
4116 let rs = rut.to_rust_string();
4117 let target = normalize_integer_type(&rs).unwrap_or("u32");
4118 return make_binary(cast_syn_expr(l, target), r);
4119 }
4120 if r_is_enum && !l_is_enum {
4121 let ls = lut.to_rust_string();
4122 let target = normalize_integer_type(&ls).unwrap_or("u32");
4123 return make_binary(l, cast_syn_expr(r, target));
4124 }
4125 if rut.is_bool() {
4127 let ls = lut.to_rust_string();
4128 if let Some(nl) = normalize_integer_type(&ls) {
4129 return make_binary(l, cast_syn_expr(r, nl));
4130 }
4131 }
4132 if lut.is_bool() {
4133 let rs = rut.to_rust_string();
4134 if let Some(nr) = normalize_integer_type(&rs) {
4135 return make_binary(cast_syn_expr(l, nr), r);
4136 }
4137 }
4138 if lut.is_float() && !rut.is_float() {
4140 let ls = lut.to_rust_string();
4141 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4142 return make_binary(l, cast_syn_expr(r, float_ty));
4143 }
4144 if rut.is_float() && !lut.is_float() {
4145 let rs = rut.to_rust_string();
4146 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4147 return make_binary(cast_syn_expr(l, float_ty), r);
4148 }
4149 let ls = lut.to_rust_string();
4151 let rs = rut.to_rust_string();
4152 if let Some(wider) = wider_integer_type(&ls, &rs) {
4153 if normalize_integer_type(&ls) != Some(wider) {
4154 return make_binary(cast_syn_expr(l, wider), r);
4155 } else {
4156 return make_binary(l, cast_syn_expr(r, wider));
4157 }
4158 }
4159 }
4160 {
4162 let make_binary = |left: syn::Expr, right: syn::Expr| -> syn::Expr {
4163 syn::Expr::Binary(syn::ExprBinary {
4164 attrs: vec![], left: Box::new(left),
4165 op: crate::syn_codegen::to_syn_binop(*op),
4166 right: Box::new(right),
4167 })
4168 };
4169 match (<, &rt) {
4170 (Some(lut), None) if lut.is_float() => {
4171 let ls = lut.to_rust_string();
4172 let float_ty = if ls == "c_float" || ls == "f32" { "f32" } else { "f64" };
4173 return make_binary(l, cast_syn_expr(r, float_ty));
4174 }
4175 (None, Some(rut)) if rut.is_float() => {
4176 let rs = rut.to_rust_string();
4177 let float_ty = if rs == "c_float" || rs == "f32" { "f32" } else { "f64" };
4178 return make_binary(cast_syn_expr(l, float_ty), r);
4179 }
4180 _ => {}
4181 }
4182 if matches!(op, BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor) {
4184 match (<, &rt) {
4185 (Some(lut), None) => {
4186 let ls = lut.to_rust_string();
4187 if let Some(nl) = normalize_integer_type(&ls) {
4188 return make_binary(l, cast_syn_expr(r, nl));
4189 }
4190 }
4191 (None, Some(rut)) => {
4192 let rs = rut.to_rust_string();
4193 if let Some(nr) = normalize_integer_type(&rs) {
4194 return make_binary(cast_syn_expr(l, nr), r);
4195 }
4196 }
4197 _ => {}
4198 }
4199 }
4200 }
4201 syn::Expr::Binary(syn::ExprBinary {
4203 attrs: vec![],
4204 left: Box::new(l),
4205 op: crate::syn_codegen::to_syn_binop(*op),
4206 right: Box::new(r),
4207 })
4208 }
4209 ExprKind::Call { func, args } => {
4210 if let Some(syn_call) = self.try_build_common_macro_fn_call(func, args, info) {
4214 return syn_call;
4215 }
4216 if let ExprKind::Ident(name) = &func.kind {
4218 let func_name = self.interner.get(*name);
4219 if func_name == "__builtin_expect" && !args.is_empty() {
4221 return self.build_syn_expr(&args[0], info);
4222 }
4223 if func_name == "__builtin_unreachable" {
4225 return syn::parse_str("std::hint::unreachable_unchecked()").unwrap();
4226 }
4227 if (func_name == "__builtin_ctz" || func_name == "__builtin_ctzl") && args.len() == 1 {
4229 let arg = self.build_syn_expr(&args[0], info);
4230 return syn::Expr::MethodCall(syn::ExprMethodCall {
4231 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4232 method: ident("trailing_zeros"), turbofish: None,
4233 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4234 });
4235 }
4236 if (func_name == "__builtin_clz" || func_name == "__builtin_clzl") && args.len() == 1 {
4237 let arg = self.build_syn_expr(&args[0], info);
4238 return syn::Expr::MethodCall(syn::ExprMethodCall {
4239 attrs: vec![], receiver: Box::new(arg), dot_token: Default::default(),
4240 method: ident("leading_zeros"), turbofish: None,
4241 paren_token: Default::default(), args: syn::punctuated::Punctuated::new(),
4242 });
4243 }
4244 if matches!(func_name, "ASSERT_IS_LITERAL" | "ASSERT_IS_PTR" | "ASSERT_NOT_PTR")
4246 && args.len() == 1
4247 {
4248 return self.build_syn_expr(&args[0], info);
4249 }
4250 if matches!(func_name, "offsetof" | "__builtin_offsetof") && args.len() == 2 {
4259 let type_name_str = if let ExprKind::Ident(name) = &args[0].kind {
4260 escape_rust_keyword(self.interner.get(*name)).to_string()
4261 } else {
4262 let s = self.build_syn_expr(&args[0], info);
4263 expr_to_string(&s)
4264 };
4265 if let Some(field_path) = self.expr_to_field_path(&args[1]) {
4266 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_name_str, field_path))
4267 .unwrap_or_else(|_| int_lit(0));
4268 }
4269 }
4270 }
4271
4272 let f_syn = self.build_syn_expr(func, info);
4274 let f_str = expr_to_string(&f_syn);
4275
4276 let callee_name = if let ExprKind::Ident(name) = &func.kind { Some(*name) } else { None };
4277 let needs_my_perl = callee_name
4278 .map(|name| self.needs_my_perl_for_call(name, args.len()))
4279 .unwrap_or(false);
4280
4281 let callee_generics = callee_name
4283 .and_then(|name| self.get_callee_generic_params(name).cloned());
4284
4285 if let Some(ref generics) = callee_generics {
4286 let mut type_args = Vec::new();
4288 let mut value_args: Vec<String> = if needs_my_perl {
4289 vec!["my_perl".to_string()]
4290 } else { vec![] };
4291 let mut value_idx = if needs_my_perl { 1usize } else { 0 };
4292 for (i, arg) in args.iter().enumerate() {
4293 if generics.contains_key(&(i as i32)) {
4294 let syn_arg = self.build_syn_expr(arg, info);
4295 type_args.push(normalize_parens(&expr_to_string(&syn_arg)));
4296 } else {
4297 value_args.push(self.build_arg_string_unified(arg, info, callee_name, value_idx));
4298 value_idx += 1;
4299 }
4300 }
4301 return syn::parse_str(&format!("{}::<{}>({})", f_str, type_args.join(", "), value_args.join(", ")))
4302 .unwrap_or_else(|_| int_lit(0));
4303 }
4304
4305 let mut arg_strs: Vec<String> = if needs_my_perl {
4307 vec!["my_perl".to_string()]
4308 } else { vec![] };
4309 let arg_offset = if needs_my_perl { 1usize } else { 0 };
4310 for (i, arg) in args.iter().enumerate() {
4311 arg_strs.push(self.build_arg_string_unified(arg, info, callee_name, i + arg_offset));
4312 }
4313 syn::parse_str(&format!("{}({})", f_str, arg_strs.join(", ")))
4314 .unwrap_or_else(|_| int_lit(0))
4315 }
4316 ExprKind::MacroCall { name, args, expanded, .. } => {
4317 if self.should_emit_as_macro_call(*name) {
4318 let name_str = escape_rust_keyword(self.interner.get(*name));
4319 let needs_my_perl = self.needs_my_perl_for_call(*name, args.len());
4320 let mut a: Vec<String> = if needs_my_perl {
4321 vec!["my_perl".to_string()]
4322 } else { vec![] };
4323 for arg in args {
4324 let arg_str = expr_to_string(&self.build_syn_expr(arg, info));
4325 a.push(normalize_parens(&arg_str));
4326 }
4327 syn::parse_str(&format!("{}({})", name_str, a.join(", ")))
4328 .unwrap_or_else(|_| int_lit(0))
4329 } else {
4330 self.build_syn_expr(expanded, info)
4331 }
4332 }
4333 ExprKind::BuiltinCall { name, args } => {
4334 let func_name = self.interner.get(*name);
4335 if matches!(func_name, "offsetof" | "__builtin_offsetof" | "STRUCT_OFFSET")
4336 && args.len() == 2
4337 {
4338 let type_str = match &args[0] {
4339 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4340 crate::ast::BuiltinArg::Expr(e) => {
4341 let s = self.build_syn_expr(e, info);
4342 expr_to_string(&s)
4343 }
4344 };
4345 let field_expr = match &args[1] {
4346 crate::ast::BuiltinArg::Expr(e) => self.expr_to_field_path(e),
4347 _ => None,
4348 };
4349 if let Some(fp) = field_expr {
4350 return syn::parse_str(&format!("std::mem::offset_of!({}, {})", type_str, fp))
4351 .unwrap_or_else(|_| int_lit(0));
4352 }
4353 }
4354 let a: Vec<String> = args.iter().map(|arg| match arg {
4356 crate::ast::BuiltinArg::Expr(e) => {
4357 let s = self.build_syn_expr(e, info);
4358 expr_to_string(&s)
4359 }
4360 crate::ast::BuiltinArg::TypeName(tn) => self.type_name_to_rust(tn),
4361 }).collect();
4362 syn::parse_str(&format!("{}({})", func_name, a.join(", ")))
4363 .unwrap_or_else(|_| int_lit(0))
4364 }
4365 ExprKind::Assign { op, lhs, rhs } => {
4366 self.build_assign_syn_expr(*op, lhs, rhs, info)
4367 }
4368 ExprKind::PreInc(inner) => {
4369 self.build_inc_dec_syn_expr(inner, info, true, false)
4370 }
4371 ExprKind::PreDec(inner) => {
4372 self.build_inc_dec_syn_expr(inner, info, false, false)
4373 }
4374 ExprKind::PostInc(inner) => {
4375 self.build_inc_dec_syn_expr(inner, info, true, true)
4376 }
4377 ExprKind::PostDec(inner) => {
4378 self.build_inc_dec_syn_expr(inner, info, false, true)
4379 }
4380 ExprKind::Assert { kind, condition } => {
4381 let assert_str = if let Some((real_cond, msg)) = decompose_assert_with_message(condition) {
4382 let c = self.build_syn_expr(real_cond, info);
4383 let c_str = expr_to_string(&c);
4384 let cond_str = self.wrap_as_bool_condition(real_cond, &c_str, info);
4385 format!("assert!({}, \"{}\")", normalize_parens(&cond_str), msg)
4386 } else {
4387 let c = self.build_syn_expr(condition, info);
4388 let c_str = expr_to_string(&c);
4389 if is_boolean_expr(condition) || self.is_bool_expr_with_dict(condition) {
4390 format!("assert!({})", normalize_parens(&c_str))
4391 } else if self.is_pointer_expr_unified(condition, info)
4392 || self.infer_expr_type_unified(condition, info).is_some_and(|ut| ut.is_pointer()) {
4393 format!("assert!(!({}).is_null())", c_str)
4397 } else {
4398 format!("assert!({} != 0)", normalize_parens(&c_str))
4399 }
4400 };
4401 let result = match kind {
4402 AssertKind::Assert => assert_str,
4403 AssertKind::AssertUnderscore => format!("{{ {}; }}", assert_str),
4404 };
4405 syn::parse_str(&result).unwrap_or_else(|_| int_lit(0))
4406 }
4407 ExprKind::StmtExpr(compound) => {
4408 if let Some(init_expr) = self.detect_mutable_ptr_pattern(compound) {
4410 return self.build_syn_expr(init_expr, info);
4411 }
4412 let mut parts: Vec<String> = Vec::new();
4416 for item in &compound.items {
4417 match item {
4418 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => {
4419 parts.push(self.build_expr_string(e, info));
4420 }
4421 BlockItem::Stmt(stmt) => {
4422 let s = match info {
4423 Some(info) => self.stmt_to_rust(stmt, info),
4424 None => self.stmt_to_rust_inline(stmt, ""),
4425 };
4426 if !s.is_empty() {
4427 parts.push(s);
4429 }
4430 }
4431 BlockItem::Decl(decl) => {
4432 self.collect_decl_types(decl);
4433 let decl_str = self.decl_to_rust_let(decl, "");
4434 for line in decl_str.lines() {
4435 let trimmed = line.trim();
4436 if !trimmed.is_empty() {
4437 parts.push(trimmed.strip_suffix(';').unwrap_or(trimmed).to_string());
4438 }
4439 }
4440 }
4441 }
4442 }
4443 let block_str = if parts.is_empty() {
4444 "{ }".to_string()
4445 } else if parts.len() == 1 {
4446 parts.pop().unwrap()
4447 } else {
4448 let last = parts.pop().unwrap();
4449 let stmts = parts.join("; ");
4450 format!("{{ {}; {} }}", stmts, last)
4451 };
4452 syn::parse_str(&block_str).unwrap_or_else(|_| int_lit(0))
4453 }
4454 ExprKind::Alignof(ty) => {
4455 let ty_str = self.type_name_to_rust(ty);
4456 syn::parse_str(&format!("std::mem::align_of::<{}>()", ty_str))
4457 .unwrap_or_else(|_| int_lit(0))
4458 }
4459 _ => {
4463 self.codegen_errors.push(format!(
4464 "unhandled ExprKind in syn codegen: {:?}",
4465 std::mem::discriminant(&expr.kind)
4466 ));
4467 int_lit(0)
4468 }
4469 }
4470 }
4471
4472 fn build_arg_string_unified(&mut self, arg: &Expr, info: Option<&MacroInferInfo>,
4476 callee: Option<InternedStr>, arg_index: usize) -> String {
4477 if info.is_some() {
4479 if let Some(name) = self.find_literal_string_ident(arg) {
4480 if let Some(callee_name) = callee {
4481 if self.callee_expects_literal_string(callee_name, arg_index) {
4482 return escape_rust_keyword(self.interner.get(*name));
4483 }
4484 }
4485 let param = escape_rust_keyword(self.interner.get(*name));
4486 if let Some(callee_name) = callee {
4490 let func_name = self.interner.get(callee_name).to_string();
4491 if let Some(expected) = self.get_callee_param_type_extended(&func_name, arg_index) {
4492 if expected.is_pointer() {
4493 return format!("{}.as_ptr() as {}", param, expected.to_rust_string());
4494 }
4495 }
4496 }
4497 return format!("{}.as_ptr() as *const c_char", param);
4498 }
4499 }
4500 if is_null_literal(arg) {
4502 if let Some(callee_name) = callee {
4503 let func_name = self.interner.get(callee_name).to_string();
4504 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4505 if expected_ut.is_pointer() {
4506 return null_ptr_expr(&expected_ut);
4507 }
4508 }
4509 }
4510 }
4511 if let Some(callee_name) = callee {
4513 let func_name = self.interner.get(callee_name);
4514 if self.callee_param_is_bool(func_name, arg_index) {
4515 match &arg.kind {
4516 ExprKind::IntLit(0) => return "false".to_string(),
4517 ExprKind::IntLit(1) => return "true".to_string(),
4518 _ => {}
4519 }
4520 }
4521 }
4522 let mut syn_expr = self.build_syn_expr(arg, info);
4524 if let Some(callee_name) = callee {
4527 let func_name = self.interner.get(callee_name).to_string();
4528 if let Some(expected_ut) = self.get_callee_param_type_extended(&func_name, arg_index) {
4529 let actual_ut = self.infer_expr_type_unified(arg, info);
4530 let actual_ty = actual_ut.as_ref().map(|ut| ut.to_rust_string());
4531 let expected_ty = expected_ut.to_rust_string();
4532 if matches!(&arg.kind, ExprKind::StringLit(_))
4536 && expected_ut.is_pointer()
4537 {
4538 syn_expr = crate::syn_codegen::method_call(syn_expr, "as_ptr", vec![]);
4539 }
4540 syn_expr = self.cast_arg_syn_if_needed(syn_expr, actual_ty.as_deref(), &expected_ty);
4541 }
4542 }
4543 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
4544 }
4545
4546 fn cast_arg_syn_if_needed(&self, arg_expr: syn::Expr,
4550 actual_ty: Option<&str>, expected_ty: &str) -> syn::Expr {
4551 use crate::syn_codegen::cast_syn_expr;
4552 if let Some(actual) = actual_ty {
4553 let actual_ut = UnifiedType::from_rust_str(actual);
4555 if self.is_rust_enum_type(&actual_ut) {
4556 if let Some(target) = normalize_integer_type(expected_ty) {
4557 return cast_syn_expr(arg_expr, target);
4558 }
4559 }
4560 let na = normalize_integer_type(actual);
4561 let ne = normalize_integer_type(expected_ty);
4562 if let (Some(a), Some(e)) = (na, ne) {
4563 if !integer_types_compatible(a, e) {
4564 return cast_syn_expr(arg_expr, e);
4565 }
4566 return arg_expr;
4567 }
4568 if actual != expected_ty {
4570 let actual_ut = UnifiedType::from_rust_str(actual);
4571 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4572 if actual_ut.is_pointer() && expected_ut.is_pointer()
4573 && is_sv_subtype_cast(&actual_ut, &expected_ut) {
4574 let cast_ty = if actual.contains("*const") {
4575 expected_ty.replace("*mut", "*const")
4576 } else {
4577 expected_ty.to_string()
4578 };
4579 return cast_syn_expr(arg_expr, &cast_ty);
4580 }
4581 if actual_ut.is_pointer() && expected_ut.is_pointer()
4587 && expected_ut.is_void_pointer()
4588 {
4589 return cast_syn_expr(arg_expr, expected_ty);
4590 }
4591 if pointer_inner_compatible(&actual_ut, &expected_ut) {
4597 let top_mut_to_const = !actual_ut.is_const_pointer()
4598 && expected_ut.is_const_pointer();
4599 let top_const_same = actual_ut.is_const_pointer()
4600 == expected_ut.is_const_pointer();
4601 let inner_exact_match = actual_ut.inner_type()
4603 .zip(expected_ut.inner_type())
4604 .is_some_and(|(a, b)| a.to_rust_string() == b.to_rust_string());
4605 let auto_coerces = (top_mut_to_const || top_const_same)
4606 && inner_exact_match;
4607 if !auto_coerces {
4608 return cast_syn_expr(arg_expr, expected_ty);
4609 }
4610 }
4611 }
4612 return arg_expr;
4613 }
4614 let expected_ut = UnifiedType::from_rust_str(expected_ty);
4616 if expected_ut.is_pointer() {
4617 if let Some(inner) = expected_ut.inner_type() {
4618 if let UnifiedType::Named(name) = inner {
4619 let n = name.as_str();
4620 if matches!(n, "SV" | "GV" | "HV" | "AV" | "CV" | "IO") {
4621 if matches!(&arg_expr, syn::Expr::Call(_) | syn::Expr::MethodCall(_)) {
4622 return cast_syn_expr(arg_expr, expected_ty);
4623 }
4624 }
4625 }
4626 }
4627 }
4628 arg_expr
4629 }
4630
4631 fn try_build_common_macro_fn_call(
4647 &mut self,
4648 func: &Expr,
4649 args: &[Expr],
4650 info: Option<&MacroInferInfo>,
4651 ) -> Option<syn::Expr> {
4652 use crate::syn_codegen::*;
4653
4654 let member_id = match &func.kind {
4655 ExprKind::Member { member, .. } | ExprKind::PtrMember { member, .. } => *member,
4656 _ => return None,
4657 };
4658
4659 let mut is_fn_ptr = self
4661 .fields_dict
4662 .and_then(|d| d.canonical_field(member_id).map(|(_, f)| f.is_fn_pointer))
4663 .unwrap_or(false);
4664
4665 if !is_fn_ptr {
4670 let field_name = self.interner.get(member_id);
4671 if let Some(ut) = self.field_type_map.get(field_name) {
4672 let ty_str = ut.to_rust_string();
4673 if type_str_is_fn_pointer(&ty_str) {
4674 is_fn_ptr = true;
4675 } else if let Some(dict) = self.rust_decl_dict {
4676 if let Some(alias) = dict.types.get(&ty_str) {
4677 if type_str_is_fn_pointer(&alias.ty) {
4678 is_fn_ptr = true;
4679 }
4680 }
4681 }
4682 }
4683 }
4684
4685 if !is_fn_ptr {
4686 return None;
4687 }
4688
4689 let field_access = self.build_syn_expr(func, info);
4691 let callee = method_call(field_access, "unwrap_unchecked", vec![]);
4693
4694 let mut punctuated = syn::punctuated::Punctuated::new();
4696 for (i, arg) in args.iter().enumerate() {
4697 let s = self.build_arg_string_unified(arg, info, None, i);
4698 let parsed = syn::parse_str(&s).unwrap_or_else(|_| int_lit(0));
4699 punctuated.push(parsed);
4700 }
4701
4702 Some(syn::Expr::Call(syn::ExprCall {
4703 attrs: vec![],
4704 func: Box::new(callee),
4705 paren_token: Default::default(),
4706 args: punctuated,
4707 }))
4708 }
4709
4710 fn build_lvalue_syn_expr(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> syn::Expr {
4712 if let ExprKind::MacroCall { expanded, .. } = &expr.kind {
4713 return self.build_syn_expr(expanded, info);
4714 }
4715 if let ExprKind::Call { func, args } = &expr.kind {
4716 if let Some(expanded) = self.try_expand_call_as_lvalue_syn(func, args, info) {
4717 return expanded;
4718 }
4719 let syn_expr = self.build_syn_expr(expr, info);
4720 let s = crate::syn_codegen::expr_to_string(&syn_expr);
4721 self.codegen_errors.push(format!("invalid lvalue: {} cannot be assigned to", s));
4722 return syn_expr;
4723 }
4724 self.build_syn_expr(expr, info)
4725 }
4726
4727 fn build_inc_dec_step_expr(&mut self, inner: &Expr, info: Option<&MacroInferInfo>,
4730 is_inc: bool) -> (syn::Expr, syn::Expr) {
4731 use crate::syn_codegen::*;
4732 let lv = self.build_lvalue_syn_expr(inner, info);
4733 let is_ptr = self.is_pointer_expr_unified(inner, info)
4734 || self.infer_expr_type_unified(inner, info).is_some_and(|ut| ut.is_pointer());
4735 let step: syn::Expr = if is_ptr {
4736 let method = if is_inc { "wrapping_add" } else { "wrapping_sub" };
4738 let call = method_call(lv.clone(), method, vec![int_lit(1)]);
4739 assign_expr(lv.clone(), call)
4740 } else {
4741 let op = if is_inc {
4742 syn::BinOp::AddAssign(Default::default())
4743 } else {
4744 syn::BinOp::SubAssign(Default::default())
4745 };
4746 assign_op_expr(lv.clone(), op, int_lit(1))
4747 };
4748 (step, lv)
4749 }
4750
4751 fn build_inc_dec_syn_expr(&mut self, inner: &Expr, info: Option<&MacroInferInfo>,
4754 is_inc: bool, is_post: bool) -> syn::Expr {
4755 use crate::syn_codegen::*;
4756 let (step, lv) = self.build_inc_dec_step_expr(inner, info, is_inc);
4757 let step_stmt = semi_stmt(step);
4758 if is_post {
4759 let save = let_stmt("_t", lv.clone());
4761 block_with_value(vec![save, step_stmt], ident_expr("_t"))
4762 } else {
4763 block_with_value(vec![step_stmt], lv)
4765 }
4766 }
4767
4768 fn build_inc_dec_stmt(&mut self, inner: &Expr, info: Option<&MacroInferInfo>,
4772 is_inc: bool, indent: &str) -> String {
4773 let (step, _lv) = self.build_inc_dec_step_expr(inner, info, is_inc);
4774 let s = normalize_parens(&crate::syn_codegen::expr_to_string(&step));
4775 format!("{}{};", indent, s)
4776 }
4777
4778 fn expr_stmt_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>, indent: &str) -> String {
4781 match &expr.kind {
4782 ExprKind::Assign { op, lhs, rhs } => {
4783 self.build_assign_stmt(op, lhs, rhs, indent, info)
4784 }
4785 ExprKind::PreInc(inner) | ExprKind::PostInc(inner) => {
4786 self.build_inc_dec_stmt(inner, info, true, indent)
4787 }
4788 ExprKind::PreDec(inner) | ExprKind::PostDec(inner) => {
4789 self.build_inc_dec_stmt(inner, info, false, indent)
4790 }
4791 _ => format!("{}{};", indent, self.build_expr_string(expr, info)),
4792 }
4793 }
4794
4795 fn build_assign_syn_expr(&mut self, op: AssignOp, lhs: &Expr, rhs: &Expr,
4798 info: Option<&MacroInferInfo>) -> syn::Expr {
4799 use crate::syn_codegen::*;
4800 let l = self.build_lvalue_syn_expr(lhs, info);
4801 let lhs_ut = self.infer_expr_type_unified(lhs, info);
4802
4803 let r: syn::Expr = if is_null_literal(rhs) && op == AssignOp::Assign {
4805 match &lhs_ut {
4806 Some(lut) if lut.is_pointer() => {
4807 if lut.is_const_pointer() {
4808 syn::parse_str("std::ptr::null()").unwrap_or_else(|_| int_lit(0))
4809 } else {
4810 syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0))
4811 }
4812 }
4813 Some(_) => int_lit(0),
4814 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
4815 }
4816 } else {
4817 let mut r_expr = self.build_syn_expr(rhs, info);
4818 if op == AssignOp::Assign {
4820 if let Some(ref lut) = lhs_ut {
4822 if lut.is_float() {
4823 if let ExprKind::IntLit(n) = &rhs.kind {
4824 r_expr = syn::parse_str(&format!("{}.0", n))
4825 .unwrap_or_else(|_| int_lit(0));
4826 }
4827 }
4828 }
4829 if let Some(ref lut) = lhs_ut {
4830 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
4831 let ls = lut.to_rust_string();
4832 let rs = rut.to_rust_string();
4833 if let (Some(nl), Some(nr)) = (
4834 normalize_integer_type(&ls),
4835 normalize_integer_type(&rs),
4836 ) {
4837 if !integer_types_compatible(nl, nr) {
4838 r_expr = cast_syn_expr(r_expr, nl);
4839 }
4840 }
4841 else if lut.is_pointer() && rut.is_pointer()
4843 && lut.is_const_pointer() != rut.is_const_pointer()
4844 {
4845 r_expr = cast_syn_expr(r_expr, &ls);
4846 }
4847 else if lut.is_pointer() && rut.is_pointer()
4849 && ls != rs
4850 && is_sv_subtype_cast(&rut, lut)
4851 {
4852 r_expr = cast_syn_expr(r_expr, &ls);
4853 }
4854 }
4855 }
4856 }
4857 r_expr
4858 };
4859
4860 if op == AssignOp::Assign {
4864 if let syn::Expr::MethodCall(mc) = &l {
4865 if mc.args.is_empty() {
4866 let method_name = mc.method.to_string();
4867 if self.is_bitfield_method(&method_name) {
4868 let setter_name = format!("set_{}", method_name);
4869 let arg_val = if let Some(dict) = self.rust_decl_dict {
4873 let ret_ty = dict.bitfield_method_types.iter()
4876 .find(|((_, m), _)| m == &method_name)
4877 .map(|(_, ty)| ty.clone());
4878 if let Some(ty) = ret_ty {
4879 cast_syn_expr(r, &ty)
4880 } else {
4881 r
4882 }
4883 } else {
4884 r
4885 };
4886 let setter_call = method_call(
4887 (*mc.receiver).clone(),
4888 &setter_name,
4889 vec![arg_val],
4890 );
4891 let stmt = semi_stmt(setter_call);
4892 return block_with_value(vec![stmt], l);
4893 }
4894 }
4895 }
4896 }
4897
4898 let stmt: syn::Stmt = match op {
4900 AssignOp::Assign => semi_stmt(assign_expr(l.clone(), r)),
4901 AssignOp::AddAssign | AssignOp::SubAssign => {
4902 let is_ptr = self.is_pointer_expr_unified(lhs, info)
4903 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer());
4904 if is_ptr {
4905 let method = if op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
4907 let r_usize = cast_syn_expr(r, "usize");
4908 let call = method_call(l.clone(), method, vec![r_usize]);
4909 semi_stmt(assign_expr(l.clone(), call))
4910 } else {
4911 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4912 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
4913 }
4914 }
4915 AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign => {
4916 let lt = &lhs_ut;
4920 let rt = self.infer_expr_type_unified(rhs, info);
4921 let r_final = {
4922 let mut casted = false;
4923 let mut ret = r;
4924 if let (Some(lut), Some(rut)) = (lt, &rt) {
4925 let ls = lut.to_rust_string();
4926 let rs = rut.to_rust_string();
4927 let nl = normalize_integer_type(&ls);
4928 let nr = normalize_integer_type(&rs);
4929 if nl.is_some() && nr.is_some() && nl != nr {
4930 ret = cast_syn_expr(ret, nl.unwrap());
4931 casted = true;
4932 }
4933 if !casted && self.is_rust_enum_type(rut) && nl.is_some() {
4935 ret = cast_syn_expr(ret, nl.unwrap());
4936 casted = true;
4937 }
4938 }
4939 if !casted {
4940 if let (Some(lut), None) = (lt, &rt) {
4941 let ls = lut.to_rust_string();
4942 if let Some(nl) = normalize_integer_type(&ls) {
4943 ret = cast_syn_expr(ret, nl);
4944 }
4945 }
4946 }
4947 ret
4948 };
4949 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4950 semi_stmt(assign_op_expr(l.clone(), syn_op, r_final))
4951 }
4952 _ => {
4953 let syn_op = c_assign_op_to_syn_compound(op).unwrap();
4954 semi_stmt(assign_op_expr(l.clone(), syn_op, r))
4955 }
4956 };
4957 block_with_value(vec![stmt], l)
4958 }
4959
4960 fn build_lvalue_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
4962 let syn_expr = self.build_lvalue_syn_expr(expr, info);
4963 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
4964 }
4965
4966 fn build_syn_expr_with_type_hint(&mut self, expr: &Expr, info: Option<&MacroInferInfo>,
4968 type_hint: Option<&str>) -> syn::Expr {
4969 use crate::syn_codegen::*;
4970 if let Some(ty) = type_hint {
4971 let ut = UnifiedType::from_rust_str(ty);
4972 if ut.is_pointer() && is_null_literal(expr) {
4973 return syn::parse_str(&null_ptr_expr(&ut)).unwrap_or_else(|_| int_lit(0));
4974 }
4975 if ut.is_bool() {
4976 match &expr.kind {
4977 ExprKind::IntLit(0) => return syn::parse_str("false").unwrap(),
4978 ExprKind::IntLit(1) => return syn::parse_str("true").unwrap(),
4979 _ => {}
4980 }
4981 }
4982 }
4983 self.build_syn_expr(expr, info)
4984 }
4985
4986 fn build_return_stmt(&mut self, expr: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
4996 use crate::syn_codegen::*;
4997 if let Some(ref rt) = self.current_return_type {
4998 if rt.is_pointer() && is_null_literal(expr) {
4999 return format!("{}return {};", indent, null_ptr_expr(rt));
5000 }
5001 if rt.is_bool() {
5002 match &expr.kind {
5003 ExprKind::IntLit(0) => return format!("{}return false;", indent),
5004 ExprKind::IntLit(1) => return format!("{}return true;", indent),
5005 _ => {
5006 let mut syn_expr = self.build_syn_expr(expr, info);
5007 if !self.is_bool_expr_with_dict(expr) && !is_bool_syn_expr(&syn_expr) {
5008 syn_expr = wrap_as_bool(syn_expr);
5009 }
5010 let s = normalize_parens(&expr_to_string(&syn_expr));
5011 return format!("{}return {};", indent, s);
5012 }
5013 }
5014 }
5015 }
5016 let mut syn_expr = self.build_syn_expr(expr, info);
5017 syn_expr = self.cast_return_syn_expr_if_needed(expr, info, syn_expr);
5018 let s = normalize_parens(&expr_to_string(&syn_expr));
5019 format!("{}return {};", indent, s)
5020 }
5021
5022 fn cast_return_syn_expr_if_needed(&self, expr: &Expr, info: Option<&MacroInferInfo>,
5025 syn_expr: syn::Expr) -> syn::Expr {
5026 let Some(ret_ut) = &self.current_return_type else { return syn_expr };
5027 let Some(expr_ut) = self.infer_expr_type_unified(expr, info) else { return syn_expr };
5028 let ret_s = ret_ut.to_rust_string();
5029 let expr_s = expr_ut.to_rust_string();
5030 if self.is_rust_enum_type(&expr_ut) {
5032 if let Some(nr) = normalize_integer_type(&ret_s) {
5033 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
5034 }
5035 }
5036 if let (Some(nr), Some(ne)) = (normalize_integer_type(&ret_s), normalize_integer_type(&expr_s)) {
5037 if !integer_types_compatible(nr, ne) {
5038 return crate::syn_codegen::cast_syn_expr(syn_expr, nr);
5039 }
5040 }
5041 if ret_ut.is_pointer() && expr_ut.is_pointer() && ret_s != expr_s
5045 && pointer_inner_compatible(ret_ut, &expr_ut)
5046 {
5047 return crate::syn_codegen::cast_syn_expr(syn_expr, &ret_s);
5048 }
5049 syn_expr
5050 }
5051
5052 fn build_assign_stmt(&mut self, op: &AssignOp, lhs: &Expr, rhs: &Expr, indent: &str, info: Option<&MacroInferInfo>) -> String {
5058 use crate::syn_codegen::*;
5059 let l = self.build_lvalue_string(lhs, info);
5060 let lhs_ut = self.infer_expr_type_unified(lhs, info);
5061
5062 let r_syn: syn::Expr = if is_null_literal(rhs) && *op == AssignOp::Assign {
5064 match &lhs_ut {
5065 Some(lut) if lut.is_pointer() => {
5066 let s = if lut.is_const_pointer() { "std::ptr::null()" } else { "std::ptr::null_mut()" };
5067 syn::parse_str(s).unwrap_or_else(|_| int_lit(0))
5068 }
5069 Some(_) => int_lit(0),
5070 None => syn::parse_str("std::ptr::null_mut()").unwrap_or_else(|_| int_lit(0)),
5071 }
5072 } else {
5073 let mut r_syn = self.build_syn_expr(rhs, info);
5074 if *op == AssignOp::Assign {
5076 if let Some(ref lut) = lhs_ut {
5078 if lut.is_float() {
5079 if let ExprKind::IntLit(n) = &rhs.kind {
5080 r_syn = syn::parse_str(&format!("{}.0", n))
5081 .unwrap_or_else(|_| int_lit(0));
5082 }
5083 }
5084 }
5085 if let Some(ref lut) = lhs_ut {
5086 if let Some(rut) = self.infer_expr_type_unified(rhs, info) {
5087 let ls = lut.to_rust_string();
5088 let rs = rut.to_rust_string();
5089 if self.is_rust_enum_type(&rut) {
5091 if let Some(nl) = normalize_integer_type(&ls) {
5092 r_syn = cast_syn_expr(r_syn, nl);
5093 }
5094 } else if let (Some(nl), Some(nr)) = (normalize_integer_type(&ls), normalize_integer_type(&rs)) {
5095 if nl != nr {
5098 r_syn = cast_syn_expr(r_syn, nl);
5099 }
5100 }
5101 if pointer_const_differs(lut, &rut) {
5104 r_syn = cast_syn_expr(r_syn, &ls);
5105 } else if lut.is_pointer() && rut.is_pointer()
5106 && ls != rs
5107 && pointer_inner_compatible(lut, &rut)
5108 {
5109 r_syn = cast_syn_expr(r_syn, &ls);
5110 }
5111 else if lut.is_pointer() && rut.is_pointer()
5114 && ls != rs
5115 && is_sv_subtype_cast(&rut, lut)
5116 {
5117 r_syn = cast_syn_expr(r_syn, &ls);
5118 }
5119 }
5120 }
5121 } else if matches!(op, AssignOp::AndAssign | AssignOp::OrAssign | AssignOp::XorAssign) {
5122 let rt = self.infer_expr_type_unified(rhs, info);
5123 if let (Some(lut), Some(rut)) = (&lhs_ut, &rt) {
5124 let ls = lut.to_rust_string();
5125 let rs = rut.to_rust_string();
5126 let nl = normalize_integer_type(&ls);
5127 let nr = normalize_integer_type(&rs);
5128 if nl.is_some() && nr.is_some() && nl != nr {
5129 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5130 } else if self.is_rust_enum_type(rut) && nl.is_some() {
5131 r_syn = cast_syn_expr(r_syn, nl.unwrap());
5133 }
5134 } else if let (Some(lut), None) = (&lhs_ut, &rt) {
5135 let ls = lut.to_rust_string();
5136 if let Some(nl) = normalize_integer_type(&ls) {
5137 r_syn = cast_syn_expr(r_syn, nl);
5138 }
5139 }
5140 }
5141 r_syn
5142 };
5143
5144 match op {
5145 AssignOp::Assign => {
5146 let r = normalize_parens(&expr_to_string(&r_syn));
5147 format!("{}{} = {};", indent, l, r)
5148 }
5149 AssignOp::AddAssign | AssignOp::SubAssign => {
5150 if self.is_pointer_expr_unified(lhs, info)
5151 || lhs_ut.as_ref().is_some_and(|ut| ut.is_pointer()) {
5152 let method = if *op == AssignOp::AddAssign { "wrapping_add" } else { "wrapping_sub" };
5153 let r_usize = cast_syn_expr(r_syn, "usize");
5154 let r = expr_to_string(&r_usize);
5155 format!("{}{} = {}.{}({});", indent, l, l, method, r)
5156 } else {
5157 let r = normalize_parens(&expr_to_string(&r_syn));
5158 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5159 }
5160 }
5161 _ => {
5162 let r = normalize_parens(&expr_to_string(&r_syn));
5163 format!("{}{} {} {};", indent, l, assign_op_to_rust(*op), r)
5164 }
5165 }
5166 }
5167
5168 fn build_expr_string(&mut self, expr: &Expr, info: Option<&MacroInferInfo>) -> String {
5170 let syn_expr = self.build_syn_expr(expr, info);
5171 normalize_parens(&crate::syn_codegen::expr_to_string(&syn_expr))
5172 }
5173
5174 fn stmt_to_rust(&mut self, stmt: &Stmt, info: &MacroInferInfo) -> String {
5176 match stmt {
5177 Stmt::Expr(Some(expr), _) => {
5178 self.expr_stmt_string(expr, Some(info), "")
5183 }
5184 Stmt::Expr(None, _) => String::new(),
5187 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, "", Some(info)),
5188 Stmt::Return(None, _) => "return;".to_string(),
5189 _ => self.todo_marker("stmt")
5190 }
5191 }
5192
5193 fn type_name_to_rust(&mut self, type_name: &crate::ast::TypeName) -> String {
5195 let base_type = self.decl_specs_to_rust(&type_name.specs);
5197
5198 let mut result = if let Some(ref decl) = type_name.declarator {
5200 self.apply_derived_to_type(&base_type, &decl.derived)
5201 } else {
5202 base_type
5203 };
5204
5205 if type_name.specs.qualifiers.is_const {
5208 if let Some(pos) = result.rfind("*mut ") {
5209 result.replace_range(pos..pos + 5, "*const ");
5210 }
5211 }
5212
5213 result
5214 }
5215
5216 fn decl_specs_to_rust(&mut self, specs: &DeclSpecs) -> String {
5218 for spec in &specs.type_specs {
5220 if let TypeSpec::TypedefName(name) = spec {
5221 if let Some(generic_name) = self.current_type_param_map.get(name) {
5223 return generic_name.clone();
5224 }
5225 let name_str = self.interner.get(*name).to_string();
5226 if !self.known_symbols.contains(&name_str) {
5228 self.codegen_errors.push(format!("undefined type: {}", name_str));
5229 }
5230 return name_str;
5231 }
5232 }
5233
5234 let mut is_void = false;
5236 let mut is_char = false;
5237 let mut is_int = false;
5238 let mut is_short = false;
5239 let mut is_long = 0usize;
5240 let mut is_unsigned = false;
5241 let mut is_float = false;
5242 let mut is_double = false;
5243
5244 for spec in &specs.type_specs {
5245 match spec {
5246 TypeSpec::Void => is_void = true,
5247 TypeSpec::Char => is_char = true,
5248 TypeSpec::Int => is_int = true,
5249 TypeSpec::Short => is_short = true,
5250 TypeSpec::Long => is_long += 1,
5251 TypeSpec::Unsigned => is_unsigned = true,
5252 TypeSpec::Signed => {}
5253 TypeSpec::Float => is_float = true,
5254 TypeSpec::Double => is_double = true,
5255 TypeSpec::Bool => return "bool".to_string(),
5256 TypeSpec::Struct(spec) => {
5257 if let Some(n) = spec.name {
5258 return self.interner.get(n).to_string();
5259 } else {
5260 return self.type_marker().to_string();
5261 }
5262 }
5263 TypeSpec::Union(spec) => {
5264 if let Some(n) = spec.name {
5265 return self.interner.get(n).to_string();
5266 } else {
5267 return self.type_marker().to_string();
5268 }
5269 }
5270 TypeSpec::Enum(spec) => {
5271 if let Some(n) = spec.name {
5272 return self.interner.get(n).to_string();
5273 } else {
5274 return "c_int".to_string();
5275 }
5276 }
5277 _ => {}
5278 }
5279 }
5280
5281 if is_void {
5282 return "()".to_string();
5283 }
5284
5285 if is_float {
5286 return "c_float".to_string();
5287 }
5288
5289 if is_double {
5290 return if is_long > 0 { "c_longdouble".to_string() } else { "c_double".to_string() };
5291 }
5292
5293 if is_char {
5294 return if is_unsigned { "c_uchar".to_string() } else { "c_char".to_string() };
5295 }
5296
5297 if is_short {
5298 return if is_unsigned { "c_ushort".to_string() } else { "c_short".to_string() };
5299 }
5300
5301 if is_long >= 2 {
5302 return if is_unsigned { "c_ulonglong".to_string() } else { "c_longlong".to_string() };
5303 }
5304
5305 if is_long == 1 {
5306 return if is_unsigned { "c_ulong".to_string() } else { "c_long".to_string() };
5307 }
5308
5309 if is_int || is_unsigned {
5310 return if is_unsigned { "c_uint".to_string() } else { "c_int".to_string() };
5311 }
5312
5313 self.type_marker().to_string()
5314 }
5315
5316 fn apply_derived_to_type(&mut self, base: &str, derived: &[DerivedDecl]) -> String {
5318 let fn_idx = derived
5320 .iter()
5321 .position(|d| matches!(d, DerivedDecl::Function(_)));
5322
5323 if let Some(idx) = fn_idx {
5324 if let DerivedDecl::Function(param_list) = &derived[idx] {
5325 let is_fn_pointer =
5327 idx > 0 && matches!(derived[idx - 1], DerivedDecl::Pointer(_));
5328
5329 let return_end = if is_fn_pointer { idx - 1 } else { idx };
5331 let return_derived = &derived[..return_end];
5332 let return_type = self.apply_simple_derived(base, return_derived);
5333
5334 let params: Vec<_> = param_list
5336 .params
5337 .iter()
5338 .map(|p| self.param_type_only(p))
5339 .collect();
5340 let params_str = params.join(", ");
5341
5342 let fn_type =
5344 format!("unsafe extern \"C\" fn({}) -> {}", params_str, return_type);
5345
5346 if is_fn_pointer {
5348 return format!("Option<{}>", fn_type);
5349 }
5350 return fn_type;
5351 }
5352 }
5353
5354 self.apply_simple_derived(base, derived)
5356 }
5357
5358 fn apply_simple_derived(&self, base: &str, derived: &[DerivedDecl]) -> String {
5360 self.apply_simple_derived_with_specs_const(base, derived, false)
5361 }
5362
5363 fn apply_simple_derived_with_specs_const(&self, base: &str, derived: &[DerivedDecl], specs_is_const: bool) -> String {
5365 let mut result = base.to_string();
5366 let mut is_first_pointer = true;
5367 for d in derived.iter().rev() {
5368 match d {
5369 DerivedDecl::Pointer(quals) => {
5370 if result == "()" {
5372 result = "c_void".to_string();
5373 }
5374 let pointee_const = if is_first_pointer {
5378 specs_is_const
5379 } else {
5380 quals.is_const
5381 };
5382 if pointee_const {
5383 result = format!("*const {}", result);
5384 } else {
5385 result = format!("*mut {}", result);
5386 }
5387 is_first_pointer = false;
5388 }
5389 DerivedDecl::Array(arr) => {
5390 if result == "()" {
5392 result = "c_void".to_string();
5393 }
5394 if let Some(ref size_expr) = arr.size {
5395 if let ExprKind::IntLit(n) = &size_expr.kind {
5397 result = format!("[{}; {}]", result, n);
5398 } else {
5399 result = format!("*mut {}", result);
5400 }
5401 } else {
5402 result = format!("*mut {}", result);
5403 }
5404 }
5405 DerivedDecl::Function(_) => {
5406 }
5408 }
5409 }
5410 result
5411 }
5412
5413 fn param_type_only(&mut self, param: &ParamDecl) -> String {
5415 let ty = self.decl_specs_to_rust(¶m.specs);
5416 if let Some(ref declarator) = param.declarator {
5417 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5421 } else {
5422 ty
5423 }
5424 }
5425
5426 pub fn generate_inline_fn(mut self, name: crate::InternedStr, func_def: &FunctionDef) -> GeneratedCode {
5428 let name_str = self.interner.get(name);
5429
5430 let usage = self.inline_fn_dict
5435 .and_then(|d| d.local_usage(name))
5436 .cloned()
5437 .unwrap_or_else(|| crate::local_usage::analyze_function(func_def));
5438 let mut_params = usage.mut_names();
5439
5440 self.mut_local_names = mut_params.clone();
5443 self.unused_param_names = {
5444 let mut set = HashSet::new();
5445 for d in &func_def.declarator.derived {
5446 if let DerivedDecl::Function(param_list) = d {
5447 for p in ¶m_list.params {
5448 if let Some(param_name) = p.declarator.as_ref().and_then(|dd| dd.name) {
5449 if usage.is_unused(param_name) {
5450 set.insert(param_name);
5451 }
5452 }
5453 }
5454 }
5455 }
5456 set
5457 };
5458 self.current_local_usage = Some(usage);
5459
5460 let params_str = self.build_fn_param_list(&func_def.declarator.derived, &mut_params);
5462
5463 let return_type = self.decl_specs_to_rust(&func_def.specs);
5465
5466 let return_derived: Vec<_> = func_def.declarator.derived.iter()
5470 .filter(|d| !matches!(d, DerivedDecl::Function(_)))
5471 .cloned()
5472 .collect();
5473 let return_type = self.apply_simple_derived_with_specs_const(&return_type, &return_derived, func_def.specs.qualifiers.is_const);
5474 self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
5475
5476 for d in &func_def.declarator.derived {
5478 if let DerivedDecl::Function(param_list) = d {
5479 for p in ¶m_list.params {
5480 if let Some(ref declarator) = p.declarator {
5481 if let Some(param_name) = declarator.name {
5482 let ty = self.param_type_only(p);
5483 self.current_param_types.insert(param_name, UnifiedType::from_rust_str(&ty));
5484 self.current_local_names.insert(param_name);
5485 }
5486 }
5487 }
5488 }
5489 }
5490
5491 self.collect_local_names_recursive(&func_def.body);
5494
5495 let is_thx_dependent = self.perl_threaded
5497 && self.is_inline_fn_thx_dependent(&func_def.declarator.derived);
5498 let thx_info = if is_thx_dependent { " [THX]" } else { "" };
5499
5500 self.dump_ast_comment_for_body(name_str, &func_def.body);
5502
5503 self.writeln(&format!("/// {}{} - inline function", name_str, thx_info));
5505 self.writeln("#[inline]");
5506 self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
5507
5508 self.writeln(&format!("pub unsafe fn {}({}) -> {} {{", name_str, params_str, return_type));
5510
5511 let needs_unsafe = func_def.function_call_count > 0 || func_def.deref_count > 0;
5513
5514 if needs_unsafe {
5515 self.writeln(" unsafe {");
5516 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5517 self.buffer.push_str(&body_str);
5518 self.writeln(" }");
5519 } else {
5520 let body_str = self.compound_stmt_to_string(&func_def.body, " ");
5521 self.buffer.push_str(&body_str);
5522 }
5523
5524 self.writeln("}");
5525 self.writeln("");
5526
5527 self.into_generated_code()
5528 }
5529
5530 fn build_fn_param_list(&mut self, derived: &[DerivedDecl], mut_params: &HashSet<InternedStr>) -> String {
5532 for d in derived {
5533 if let DerivedDecl::Function(param_list) = d {
5534 if is_void_only_param_list(¶m_list.params) {
5538 return String::new();
5539 }
5540 let params: Vec<_> = param_list.params.iter()
5541 .map(|p| self.param_decl_to_rust(p, mut_params))
5542 .collect();
5543 let mut result = params.join(", ");
5544 if param_list.is_variadic {
5545 if !result.is_empty() {
5546 result.push_str(", ");
5547 }
5548 result.push_str("...");
5549 }
5550 return result;
5551 }
5552 }
5553 String::new()
5554 }
5555
5556 fn is_inline_fn_thx_dependent(&self, derived: &[DerivedDecl]) -> bool {
5560 for d in derived {
5561 if let DerivedDecl::Function(param_list) = d {
5562 if let Some(first_param) = param_list.params.first() {
5563 if let Some(ref declarator) = first_param.declarator {
5564 if let Some(name) = declarator.name {
5565 let name_str = self.interner.get(name);
5566 return name_str == "my_perl";
5567 }
5568 }
5569 }
5570 return false;
5571 }
5572 }
5573 false
5574 }
5575
5576 fn param_decl_to_rust(&mut self, param: &ParamDecl, mut_params: &HashSet<InternedStr>) -> String {
5578 let param_name_interned = param.declarator
5579 .as_ref()
5580 .and_then(|d| d.name);
5581 let name = match param_name_interned {
5582 Some(n) if self.unused_param_names.contains(&n) => {
5585 format!("_{}", self.interner.get(n))
5586 }
5587 Some(n) => escape_rust_keyword(self.interner.get(n)),
5588 None => "_".to_string(),
5589 };
5590
5591 let ty = self.decl_specs_to_rust(¶m.specs);
5592
5593 let ty = if let Some(ref declarator) = param.declarator {
5595 self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5596 } else {
5597 ty
5598 };
5599
5600 if let Some(n) = param_name_interned {
5602 self.current_param_types.insert(n, UnifiedType::from_rust_str(&ty));
5603 }
5604
5605 let mut_prefix = if param_name_interned.is_some_and(|n| mut_params.contains(&n)) {
5606 "mut "
5607 } else {
5608 ""
5609 };
5610
5611 format!("{}{}: {}", mut_prefix, name, ty)
5612 }
5613
5614 fn decl_to_rust_let(&mut self, decl: &Declaration, indent: &str) -> String {
5616 let mut result = String::new();
5617
5618 let base_type = self.decl_specs_to_rust(&decl.specs);
5620
5621 for init_decl in &decl.declarators {
5623 let name = init_decl.declarator.name
5624 .map(|n| escape_rust_keyword(self.interner.get(n)))
5625 .unwrap_or_else(|| "_".to_string());
5626
5627 let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
5629
5630 if let Some(ref init) = init_decl.init {
5632 match init {
5633 Initializer::Expr(expr) => {
5634 let mut init_syn = self.build_syn_expr(expr, None);
5639 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5640 let decl_s = ty.clone();
5641 let expr_s = expr_ut.to_rust_string();
5642 let nd = normalize_integer_type(&decl_s);
5643 let ne = normalize_integer_type(&expr_s);
5644 if let (Some(d), Some(e)) = (nd, ne) {
5645 if !integer_types_compatible(d, e) {
5646 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, d);
5647 }
5648 }
5649 }
5650 let decl_is_mut_ptr = ty.contains("*mut ") && !ty.contains("*const ");
5655 let decl_is_const_ptr = ty.contains("*const ") && !ty.contains("*mut ");
5656 if let Some(expr_ut) = self.infer_expr_type_inline(expr) {
5657 if expr_ut.is_pointer() {
5658 if decl_is_mut_ptr && expr_ut.is_const_pointer() {
5659 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5660 } else if decl_is_const_ptr && !expr_ut.is_const_pointer() {
5661 init_syn = crate::syn_codegen::cast_syn_expr(init_syn, &ty);
5662 }
5663 }
5664 }
5665 let init_expr = normalize_parens(&crate::syn_codegen::expr_to_string(&init_syn));
5666 let init_expr = if is_null_literal(expr) && ty.contains("*mut") {
5668 "std::ptr::null_mut()".to_string()
5669 } else if is_null_literal(expr) && ty.contains("*const") {
5670 "std::ptr::null()".to_string()
5671 } else {
5672 init_expr
5673 };
5674 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5675 result.push_str(&format!("{}let {}{}: {} = {};\n", indent, mut_kw, name, ty, strip_outer_parens(&init_expr)));
5676 }
5677 Initializer::List(_) => {
5678 result.push_str(&format!("{}let {}: {} = /* init list */;\n", indent, name, ty));
5680 }
5681 }
5682 } else {
5683 let mut_kw = if init_decl.declarator.name.is_some_and(|n| self.mut_local_names.contains(&n)) { "mut " } else { "" };
5688 let needs_zeroed = init_decl.declarator.name.is_some_and(|n| {
5689 self.current_local_usage.as_ref().is_some_and(|u| u.needs_zeroed_init(n))
5690 });
5691 if needs_zeroed {
5692 result.push_str(&format!(
5693 "{}let {}{}: {} = std::mem::zeroed(); // C: uninitialized out-param\n",
5694 indent, mut_kw, name, ty));
5695 } else {
5696 result.push_str(&format!("{}let {}{}: {}; // uninitialized\n", indent, mut_kw, name, ty));
5697 }
5698 }
5699 }
5700
5701 result
5702 }
5703
5704 fn compound_stmt_to_string(&mut self, stmt: &CompoundStmt, indent: &str) -> String {
5706 let mut result = String::new();
5707 for item in &stmt.items {
5708 match item {
5709 BlockItem::Decl(decl) => {
5710 self.collect_decl_types(decl);
5711 result.push_str(&self.decl_to_rust_let(decl, indent));
5712 }
5713 BlockItem::Stmt(s) => {
5714 let rust_stmt = self.stmt_to_rust_inline(s, indent);
5715 if !rust_stmt.is_empty() {
5716 result.push_str(&rust_stmt);
5717 result.push('\n');
5718 }
5719 }
5720 }
5721 }
5722 result
5723 }
5724
5725 fn stmt_to_rust_inline(&mut self, stmt: &Stmt, indent: &str) -> String {
5727 match stmt {
5728 Stmt::Expr(Some(expr), _) => {
5729 self.expr_stmt_string(expr, None, indent)
5731 }
5732 Stmt::Expr(None, _) => String::new(),
5733 Stmt::Return(Some(expr), _) => self.build_return_stmt(expr, indent, None),
5734 Stmt::Return(None, _) => format!("{}return;", indent),
5735 Stmt::If { cond, then_stmt, else_stmt, .. } => {
5736 let cond_str = self.build_expr_string(cond, None);
5737 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5739 let mut result = format!("{}if {} {{\n", indent, normalize_parens(&cond_bool));
5740 let nested_indent = format!("{} ", indent);
5741 result.push_str(&self.stmt_to_rust_inline(then_stmt, &nested_indent));
5742 result.push_str("\n");
5743 result.push_str(&format!("{}}}", indent));
5744 if let Some(else_stmt) = else_stmt {
5745 result.push_str(" else {\n");
5746 result.push_str(&self.stmt_to_rust_inline(else_stmt, &nested_indent));
5747 result.push_str("\n");
5748 result.push_str(&format!("{}}}", indent));
5749 }
5750 result
5751 }
5752 Stmt::Compound(compound) => {
5753 let mut result = format!("{}{{\n", indent);
5754 for item in &compound.items {
5755 match item {
5756 BlockItem::Stmt(s) => {
5757 let nested_indent = format!("{} ", indent);
5758 result.push_str(&self.stmt_to_rust_inline(s, &nested_indent));
5759 result.push_str("\n");
5760 }
5761 BlockItem::Decl(decl) => {
5762 self.collect_decl_types(decl);
5763 let nested_indent = format!("{} ", indent);
5764 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5765 }
5766 }
5767 }
5768 result.push_str(&format!("{}}}", indent));
5769 result
5770 }
5771 Stmt::While { cond, body, .. } => {
5772 let cond_str = self.build_expr_string(cond, None);
5773 let cond_bool = self.wrap_as_bool_condition_inline(cond, &cond_str);
5777 let mut result = format!("{}while {} {{\n", indent, normalize_parens(&cond_bool));
5778 let nested_indent = format!("{} ", indent);
5779 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5780 result.push_str("\n");
5781 result.push_str(&format!("{}}}", indent));
5782 result
5783 }
5784 Stmt::For { init, cond, step, body, .. } => {
5785 let mut result = format!("{}{{\n", indent);
5786 let nested_indent = format!("{} ", indent);
5787
5788 if let Some(for_init) = init {
5790 match for_init {
5791 ForInit::Expr(expr) => {
5792 result.push_str(&self.expr_stmt_string(expr, None, &nested_indent));
5793 result.push('\n');
5794 }
5795 ForInit::Decl(decl) => {
5796 self.collect_decl_types(decl);
5797 result.push_str(&self.decl_to_rust_let(decl, &nested_indent));
5798 }
5799 }
5800 }
5801
5802 if let Some(cond_expr) = cond {
5804 let cond_str = self.build_expr_string(cond_expr, None);
5805 let cond_bool = self.wrap_as_bool_condition_inline(cond_expr, &cond_str);
5807 result.push_str(&format!("{}while {} {{\n", nested_indent, normalize_parens(&cond_bool)));
5808 } else {
5809 result.push_str(&format!("{}loop {{\n", nested_indent));
5810 }
5811
5812 let body_indent = format!("{} ", nested_indent);
5813
5814 result.push_str(&self.stmt_to_rust_inline(body, &body_indent));
5816 result.push_str("\n");
5817
5818 if let Some(step_expr) = step {
5820 result.push_str(&self.expr_stmt_string(step_expr, None, &body_indent));
5821 result.push('\n');
5822 }
5823
5824 result.push_str(&format!("{}}}\n", nested_indent));
5825 result.push_str(&format!("{}}}", indent));
5826 result
5827 }
5828 Stmt::DoWhile { body, cond, .. } => {
5829 if is_zero_constant(cond) {
5832 if !stmt_contains_top_level_break(body) {
5837 let mut result = format!("{}{{\n", indent);
5838 let nested_indent = format!("{} ", indent);
5839 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5840 result.push_str("\n");
5841 result.push_str(&format!("{}}}", indent));
5842 return result;
5843 }
5844 let mut result = format!("{}loop {{\n", indent);
5845 let nested_indent = format!("{} ", indent);
5846 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5847 result.push_str("\n");
5848 result.push_str(&format!("{} break;\n", indent));
5849 result.push_str(&format!("{}}}", indent));
5850 return result;
5851 }
5852
5853 let mut result = format!("{}loop {{\n", indent);
5855 let nested_indent = format!("{} ", indent);
5856 result.push_str(&self.stmt_to_rust_inline(body, &nested_indent));
5857 result.push_str("\n");
5858 let cond_str = self.build_expr_string(cond, None);
5859 let break_cond = if is_boolean_expr(cond) {
5863 normalize_parens(&format!("!({})", cond_str))
5864 } else {
5865 format!("{} == 0", cond_str)
5866 };
5867 result.push_str(&format!("{} if {} {{ break; }}\n", indent, break_cond));
5868 result.push_str(&format!("{}}}", indent));
5869 result
5870 }
5871 Stmt::Switch { expr, body, .. } => {
5872 let expr_str = self.build_expr_string(expr, None);
5873 let mut result = format!("{}match {} {{\n", indent, expr_str);
5874 let nested_indent = format!("{} ", indent);
5875
5876 self.collect_switch_cases(body, &nested_indent, &mut result);
5878
5879 result.push_str(&format!("{}}}", indent));
5880 result
5881 }
5882 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5883 let case_val = self.build_expr_string(case_expr, None);
5885 let mut result = format!("{}{} => {{\n", indent, case_val);
5886 let body_indent = format!("{} ", indent);
5887 result.push_str(&self.stmt_to_rust_inline(case_stmt, &body_indent));
5888 result.push_str("\n");
5889 result.push_str(&format!("{}}}", indent));
5890 result
5891 }
5892 Stmt::Default { stmt: default_stmt, .. } => {
5893 let mut result = format!("{}_ => {{\n", indent);
5894 let body_indent = format!("{} ", indent);
5895 result.push_str(&self.stmt_to_rust_inline(default_stmt, &body_indent));
5896 result.push_str("\n");
5897 result.push_str(&format!("{}}}", indent));
5898 result
5899 }
5900 Stmt::Goto(label, _) => {
5901 let label_str = self.interner.get(*label);
5902 format!("{}break '{}; // goto", indent, label_str)
5903 }
5904 Stmt::Label { name, stmt: label_stmt, .. } => {
5905 let label_str = self.interner.get(*name);
5906 let mut result = format!("{}'{}: {{\n", indent, label_str);
5907 let nested_indent = format!("{} ", indent);
5908 result.push_str(&self.stmt_to_rust_inline(label_stmt, &nested_indent));
5909 result.push_str("\n");
5910 result.push_str(&format!("{}}}", indent));
5911 result
5912 }
5913 Stmt::Break(_) => format!("{}break;", indent),
5914 Stmt::Continue(_) => format!("{}continue;", indent),
5915 _ => self.todo_marker(&format!("{:?}", std::mem::discriminant(stmt)))
5916 }
5917 }
5918
5919 fn collect_switch_cases(&mut self, stmt: &Stmt, indent: &str, result: &mut String) {
5921 struct SwitchCase {
5923 patterns: Vec<String>, body_stmts: Vec<String>,
5925 is_default: bool,
5926 }
5927
5928 let mut cases: Vec<SwitchCase> = Vec::new();
5929 let body_indent = format!("{} ", indent);
5930
5931 fn collect_items<'a>(stmt: &'a Stmt, items: &mut Vec<&'a BlockItem>) {
5933 if let Stmt::Compound(compound) = stmt {
5934 for item in &compound.items {
5935 items.push(item);
5936 }
5937 }
5938 }
5939
5940 fn flatten_case_chain<'a>(stmt: &'a Stmt, patterns: &mut Vec<&'a Expr>) -> (&'a Stmt, bool) {
5942 match stmt {
5943 Stmt::Case { expr, stmt: inner_stmt, .. } => {
5944 patterns.push(expr);
5945 flatten_case_chain(inner_stmt, patterns)
5946 }
5947 Stmt::Default { stmt: inner_stmt, .. } => {
5948 (inner_stmt, true)
5950 }
5951 other => (other, false)
5952 }
5953 }
5954
5955 let mut items: Vec<&BlockItem> = Vec::new();
5956 collect_items(stmt, &mut items);
5957
5958 for item in items {
5959 match item {
5960 BlockItem::Stmt(s) => {
5961 match s {
5962 Stmt::Case { expr: case_expr, stmt: case_stmt, .. } => {
5963 let mut patterns: Vec<&Expr> = vec![case_expr];
5965 let (final_stmt, has_default) = flatten_case_chain(case_stmt, &mut patterns);
5966
5967 let pattern_strs: Vec<String> = patterns.iter()
5969 .map(|e| self.expr_to_rust_pattern(e))
5970 .collect();
5971
5972 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
5974 vec![]
5975 } else {
5976 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
5977 };
5978 cases.push(SwitchCase {
5979 patterns: pattern_strs,
5980 body_stmts,
5981 is_default: has_default,
5982 });
5983 }
5984 Stmt::Default { stmt: default_stmt, .. } => {
5985 let mut patterns: Vec<&Expr> = Vec::new();
5987 let (final_stmt, _) = flatten_case_chain(default_stmt, &mut patterns);
5988
5989 let pattern_strs: Vec<String> = patterns.iter()
5991 .map(|e| self.expr_to_rust_pattern(e))
5992 .collect();
5993
5994 let body_stmts = if matches!(final_stmt, Stmt::Break(_)) {
5996 vec![]
5997 } else {
5998 vec![self.stmt_to_rust_inline(final_stmt, &body_indent)]
5999 };
6000 cases.push(SwitchCase {
6001 patterns: pattern_strs,
6002 body_stmts,
6003 is_default: true,
6004 });
6005 }
6006 Stmt::Break(_) => {
6007 }
6010 other => {
6011 if let Some(last) = cases.last_mut() {
6013 last.body_stmts.push(self.stmt_to_rust_inline(other, &body_indent));
6014 }
6015 }
6017 }
6018 }
6019 BlockItem::Decl(decl) => {
6020 self.collect_decl_types(decl);
6021 if let Some(last) = cases.last_mut() {
6023 last.body_stmts.push(self.decl_to_rust_let(decl, &body_indent));
6024 }
6025 }
6026 }
6027 }
6028
6029 let has_default = cases.iter().any(|c| c.is_default);
6031 for case in &cases {
6032 let pattern = if case.is_default {
6033 if case.patterns.is_empty() {
6034 "_".to_string()
6035 } else {
6036 format!("{} | _", case.patterns.join(" | "))
6038 }
6039 } else {
6040 case.patterns.join(" | ")
6041 };
6042
6043 result.push_str(&format!("{}{} => {{\n", indent, pattern));
6044 for stmt in &case.body_stmts {
6045 result.push_str(stmt);
6046 result.push_str("\n");
6047 }
6048 result.push_str(&format!("{}}}\n", indent));
6049 }
6050 if !has_default {
6054 result.push_str(&format!("{}_ => {{}}\n", indent));
6055 }
6056 }
6057
6058 fn expr_to_field_path(&self, expr: &Expr) -> Option<String> {
6062 match &expr.kind {
6063 ExprKind::Ident(name) => {
6064 Some(self.interner.get(*name).to_string())
6065 }
6066 ExprKind::Member { expr: base, member } => {
6067 let base_path = self.expr_to_field_path(base)?;
6068 let member_name = self.interner.get(*member);
6069 Some(format!("{}.{}", base_path, member_name))
6070 }
6071 _ => None,
6072 }
6073 }
6074
6075
6076 fn expr_to_rust_pattern(&mut self, expr: &Expr) -> String {
6082 match &expr.kind {
6083 ExprKind::Ident(name) => {
6084 if let Some(enum_name) = self.enum_dict.get_enum_for_variant(*name) {
6086 let enum_str = self.interner.get(enum_name);
6087 let variant_str = self.interner.get(*name);
6088 format!("crate::{}::{}", enum_str, variant_str)
6089 } else {
6090 escape_rust_keyword(self.interner.get(*name))
6091 }
6092 }
6093 _ => self.build_expr_string(expr, None)
6095 }
6096 }
6097}
6098
6099impl<'a, W: Write> CodegenDriver<'a, W> {
6100 pub fn new(
6102 writer: W,
6103 interner: &'a StringInterner,
6104 enum_dict: &'a EnumDict,
6105 macro_ctx: &'a MacroInferContext,
6106 bindings_info: BindingsInfo,
6107 config: CodegenConfig,
6108 ) -> Self {
6109 Self {
6110 writer,
6111 interner,
6112 enum_dict,
6113 macro_ctx,
6114 bindings_info,
6115 config,
6116 stats: CodegenStats::default(),
6117 report: CodegenReport::default(),
6118 used_libc_fns: HashSet::new(),
6119 successfully_generated_inlines: HashSet::new(),
6120 generatable_macros: HashSet::new(),
6121 const_pointer_params: HashMap::new(),
6122 bool_return_macros: HashSet::new(),
6123 perl_threaded: true,
6126 }
6127 }
6128
6129 pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
6131 self.perl_threaded = threaded;
6132 self
6133 }
6134
6135 pub fn stats(&self) -> &CodegenStats {
6137 &self.stats
6138 }
6139
6140 pub fn report(&self) -> &CodegenReport {
6142 &self.report
6143 }
6144
6145 pub fn generate(&mut self, result: &InferResult) -> io::Result<()> {
6150 self.perl_threaded = result.perl_build_mode.is_threaded();
6152
6153 let missing_structs = crate::struct_emitter::emit_missing_structs(
6156 &result.fields_dict,
6157 result.rust_decl_dict.as_ref(),
6158 self.interner,
6159 );
6160 let static_arrays = crate::static_array_emitter::emit_static_arrays(
6161 &result.global_const_dict,
6162 &result.fields_dict,
6163 result.rust_decl_dict.as_ref(),
6164 self.interner,
6165 );
6166 for n in &static_arrays.emitted_names {
6170 self.bindings_info.static_arrays.insert(n.clone());
6171 }
6172 for (n, t) in &static_arrays.emitted_types {
6173 self.bindings_info.static_types.insert(n.clone(), t.clone());
6174 }
6175
6176 let mut known_symbols = KnownSymbols::new(result, self.interner);
6178 for n in &missing_structs.emitted_struct_names {
6179 known_symbols.insert(n.clone());
6180 }
6181 for n in &missing_structs.emitted_typedef_names {
6182 known_symbols.insert(n.clone());
6183 }
6184
6185 for (struct_name, methods) in &missing_structs.bitfield_methods {
6189 self.bindings_info
6190 .bitfield_methods
6191 .entry(struct_name.clone())
6192 .or_default()
6193 .extend(methods.iter().cloned());
6194 }
6195 writeln!(self.writer, "// Auto-generated Rust bindings")?;
6200 writeln!(self.writer, "// Generated by libperl-macrogen")?;
6203 writeln!(self.writer)?;
6204
6205 self.generate_use_statements()?;
6207
6208 self.generate_enum_imports(result)?;
6210
6211 if !missing_structs.source.is_empty() {
6213 self.writer.write_all(missing_structs.source.as_bytes())?;
6214 }
6215
6216 if !static_arrays.source.is_empty() {
6218 self.writer.write_all(static_arrays.source.as_bytes())?;
6219 }
6220
6221 self.precompute_macro_generability(result, &known_symbols);
6223
6224 for (&name, info) in &result.infer_ctx.macros {
6226 if info.is_bool_return {
6227 self.bool_return_macros.insert(name);
6228 }
6229 }
6230
6231 if self.config.emit_inline_fns {
6233 self.generate_inline_fns(result, &known_symbols)?;
6234 }
6235
6236 if self.config.emit_macros {
6238 self.generate_macros(result, &known_symbols)?;
6239 }
6240
6241 if !self.used_libc_fns.is_empty() {
6243 let mut fns: Vec<_> = self.used_libc_fns.iter().cloned().collect();
6244 fns.sort();
6245 writeln!(self.writer, "use libc::{{{}}};", fns.join(", "))?;
6246 }
6247
6248 Ok(())
6249 }
6250
6251 fn generate_use_statements(&mut self) -> io::Result<()> {
6253 let statements = if self.config.use_statements.is_empty() {
6254 CodegenConfig::default_use_statements()
6255 } else {
6256 self.config.use_statements.clone()
6257 };
6258
6259 if !statements.is_empty() {
6260 for stmt in &statements {
6261 writeln!(self.writer, "{};", stmt)?;
6262 }
6263 writeln!(self.writer)?;
6264 }
6265
6266 Ok(())
6267 }
6268
6269 fn generate_enum_imports(&mut self, result: &InferResult) -> io::Result<()> {
6273 let enum_names = result.enum_dict.target_enum_names(self.interner);
6274 let bindings_enums = result.rust_decl_dict.as_ref().map(|d| &d.enums);
6275
6276 let filtered_names: Vec<_> = enum_names
6278 .into_iter()
6279 .filter(|name| {
6280 bindings_enums.map_or(true, |enums| enums.contains(*name))
6281 })
6282 .collect();
6283
6284 if !filtered_names.is_empty() {
6285 writeln!(self.writer, "// Enum variant imports")?;
6286 for name in filtered_names {
6287 writeln!(self.writer, "#[allow(unused_imports)]")?;
6288 writeln!(self.writer, "use crate::{}::*;", name)?;
6289 }
6290 writeln!(self.writer)?;
6291 }
6292
6293 Ok(())
6294 }
6295
6296 fn precompute_macro_generability(&mut self, result: &InferResult, known_symbols: &KnownSymbols) {
6302 let macros: Vec<_> = result.infer_ctx.macros.iter()
6304 .filter(|(_, info)| self.should_include_macro(info))
6305 .collect();
6306 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6307
6308 let sorted_names = self.topological_sort_macros(¯os);
6310
6311 for name in sorted_names {
6312 let info = result.infer_ctx.macros.get(&name).unwrap();
6313
6314 if info.apidoc_suppressed {
6320 continue;
6321 }
6322
6323 let has_cascade_failure = info.called_functions.iter().any(|called| {
6328 if included_set.contains(called) {
6329 return result.infer_ctx.macros.get(called)
6330 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6331 .unwrap_or(false)
6332 && !self.generatable_macros.contains(called);
6333 }
6334 false
6335 });
6336 if has_cascade_failure {
6337 continue;
6338 }
6339
6340 let status = self.get_macro_status(info);
6342 if status == GenerateStatus::Success {
6343 let codegen = RustCodegen::new(
6345 self.interner, self.enum_dict, self.macro_ctx,
6346 self.bindings_info.clone(), &known_symbols,
6347 result.rust_decl_dict.as_ref(), Some(&result.inline_fn_dict),
6348 ).with_perl_threaded(self.perl_threaded);
6349 let generated = codegen.generate_macro(info);
6350 if generated.is_complete() && !generated.has_unresolved_names() {
6351 self.generatable_macros.insert(name);
6352 }
6353 }
6354 }
6355 }
6356
6357 pub fn generate_inline_fns(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6364 writeln!(self.writer, "// =============================================================================")?;
6365 writeln!(self.writer, "// Inline Functions")?;
6366 writeln!(self.writer, "// =============================================================================")?;
6367 writeln!(self.writer)?;
6368
6369 let mut fns: Vec<_> = result.inline_fn_dict.iter()
6371 .filter(|(_, func_def)| func_def.is_target)
6372 .collect();
6373 fns.sort_by_key(|(name, _)| self.interner.get(**name));
6374
6375 let inline_set: HashSet<InternedStr> = fns.iter().map(|(n, _)| **n).collect();
6377
6378 enum InlineGenResult {
6380 CallsUnavailable,
6381 ContainsGoto,
6382 UnresolvedNames { code: String, unresolved: Vec<String> },
6383 CodegenError { code: String, errors: Vec<String> },
6384 Incomplete { code: String },
6385 Success { code: String, used_libc: HashSet<String> },
6386 Suppressed { reason: String },
6387 }
6388
6389 let mut gen_results: Vec<(InternedStr, InlineGenResult)> = Vec::new();
6390
6391 for (name, func_def) in &fns {
6392 if result.inline_fn_dict.is_apidoc_suppressed(**name) {
6395 let n_str = self.interner.get(**name);
6396 let reason = result.apidoc_patches.skip_reason(n_str)
6397 .unwrap_or("apidoc skip_codegen")
6398 .to_string();
6399 gen_results.push((**name,
6400 InlineGenResult::Suppressed { reason }));
6401 continue;
6402 }
6403
6404 if result.inline_fn_dict.is_calls_unavailable(**name) {
6406 gen_results.push((**name, InlineGenResult::CallsUnavailable));
6407 continue;
6408 }
6409
6410 if block_items_contain_goto(&func_def.body.items) {
6411 gen_results.push((**name, InlineGenResult::ContainsGoto));
6412 continue;
6413 }
6414
6415 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))
6416 .with_perl_threaded(self.perl_threaded)
6417 .with_dump_ast_for(self.config.dump_ast_for.clone())
6418 .with_dump_types_for(self.config.dump_types_for.clone())
6419 .with_fields_dict(&result.fields_dict)
6420 .with_bool_return(false, self.bool_return_macros.clone());
6421 let generated = codegen.generate_inline_fn(**name, func_def);
6422
6423 if generated.has_unresolved_names() {
6424 gen_results.push((**name, InlineGenResult::UnresolvedNames {
6425 code: generated.code,
6426 unresolved: generated.unresolved_names,
6427 }));
6428 } else if !generated.codegen_errors.is_empty() {
6429 gen_results.push((**name, InlineGenResult::CodegenError {
6430 code: generated.code,
6431 errors: generated.codegen_errors,
6432 }));
6433 } else if generated.is_complete() {
6434 gen_results.push((**name, InlineGenResult::Success {
6435 code: generated.code,
6436 used_libc: generated.used_libc_fns,
6437 }));
6438 } else {
6439 gen_results.push((**name, InlineGenResult::Incomplete {
6440 code: generated.code,
6441 }));
6442 }
6443 }
6444
6445 for (name, gen_result) in &gen_results {
6447 if matches!(gen_result, InlineGenResult::Success { .. }) {
6448 self.successfully_generated_inlines.insert(*name);
6449 }
6450 }
6451
6452 let mut changed = true;
6457 while changed {
6458 changed = false;
6459 let current_success = self.successfully_generated_inlines.clone();
6460 for (name, _) in &gen_results {
6461 if !current_success.contains(name) {
6462 continue;
6463 }
6464 if let Some(calls) = result.inline_fn_dict.get_called_functions(*name) {
6465 let has_unavailable = calls.iter().any(|called| {
6466 if inline_set.contains(called) && !current_success.contains(called) {
6468 return true;
6469 }
6470 if let Some(macro_info) = result.infer_ctx.macros.get(called) {
6472 if macro_info.is_target && self.should_include_macro(macro_info) {
6473 if !self.generatable_macros.contains(called) {
6474 return true;
6475 }
6476 }
6477 }
6478 false
6479 });
6480 if has_unavailable {
6481 self.successfully_generated_inlines.remove(name);
6482 changed = true;
6483 }
6484 }
6485 }
6486 }
6487
6488 for (name, gen_result) in gen_results {
6490 match gen_result {
6491 InlineGenResult::CallsUnavailable => {
6492 let name_str = self.interner.get(name);
6493 let calls = result.inline_fn_dict.get_called_functions(name);
6494 let absent: Vec<String> = calls
6497 .map(|cs| cs.iter()
6498 .filter(|c| {
6499 let fn_name = self.interner.get(**c);
6500 !self.is_function_available(**c, fn_name, result)
6501 })
6502 .map(|c| self.interner.get(*c).to_string())
6503 .collect())
6504 .unwrap_or_default();
6505 let cascade_deps: Vec<String> = calls
6506 .map(|cs| cs.iter()
6507 .filter(|c| {
6508 let is_unavailable_inline = result.inline_fn_dict.get(**c).is_some()
6509 && result.inline_fn_dict.is_unavailable_for_codegen(**c);
6510 let is_unavailable_macro = result.infer_ctx.macros.get(c)
6511 .map(|info| info.is_unavailable_for_codegen())
6512 .unwrap_or(false);
6513 is_unavailable_inline || is_unavailable_macro
6514 })
6515 .map(|c| self.interner.get(*c).to_string())
6516 .collect())
6517 .unwrap_or_default();
6518 let mut cascade_deps = cascade_deps;
6520 cascade_deps.sort();
6521 let mut absent = absent;
6522 absent.sort();
6523 if absent.is_empty() {
6524 writeln!(self.writer,
6525 "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6526 name_str, cascade_deps.join(", "))?;
6527 self.report.record_skip(name_str, format!(
6528 "CASCADE_UNAVAILABLE: dependency not generated: {}",
6529 cascade_deps.join(", ")));
6530 } else {
6531 writeln!(self.writer,
6532 "// [CALLS_UNAVAILABLE] {} - calls unavailable function(s): {}",
6533 name_str, absent.join(", "))?;
6534 self.report.record_skip(name_str, format!(
6535 "CALLS_UNAVAILABLE: calls unavailable function(s): {}",
6536 absent.join(", ")));
6537 }
6538 writeln!(self.writer)?;
6539 self.stats.inline_fns_cascade_unavailable += 1;
6540 }
6541 InlineGenResult::ContainsGoto => {
6542 let name_str = self.interner.get(name);
6543 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6544 writeln!(self.writer)?;
6545 self.report.record_skip(name_str, "CONTAINS_GOTO: excluded (contains goto)");
6546 self.stats.inline_fns_contains_goto += 1;
6547 }
6548 InlineGenResult::Suppressed { reason } => {
6549 let name_str = self.interner.get(name);
6550 writeln!(self.writer,
6551 "// [CODEGEN_SUPPRESSED] {} - inline function (apidoc patch)",
6552 name_str)?;
6553 writeln!(self.writer, "// Reason: {}", reason)?;
6554 writeln!(self.writer)?;
6555 self.report.record_skip(name_str, format!(
6556 "CODEGEN_SUPPRESSED (apidoc patch): {}", reason));
6557 }
6558 InlineGenResult::UnresolvedNames { code, unresolved } => {
6559 let name_str = self.interner.get(name);
6560 let mut unresolved = unresolved.clone();
6561 unresolved.sort(); writeln!(self.writer, "// [UNRESOLVED_NAMES] {} - inline function", name_str)?;
6563 writeln!(self.writer, "// Unresolved: {}", unresolved.join(", "))?;
6564 for line in code.lines() {
6565 writeln!(self.writer, "// {}", line)?;
6566 }
6567 writeln!(self.writer)?;
6568 self.report.record_skip(name_str, format!(
6569 "UNRESOLVED_NAMES: {}", unresolved.join(", ")));
6570 self.stats.inline_fns_unresolved_names += 1;
6571 }
6572 InlineGenResult::CodegenError { code, errors } => {
6573 let name_str = self.interner.get(name);
6574 writeln!(self.writer, "// [CODEGEN_ERROR] {} - inline function", name_str)?;
6575 for err in &errors {
6576 writeln!(self.writer, "// {}", err)?;
6577 }
6578 for line in code.lines() {
6579 writeln!(self.writer, "// {}", line)?;
6580 }
6581 writeln!(self.writer)?;
6582 self.report.record_skip(name_str, format!(
6583 "CODEGEN_ERROR: {}", errors.join("; ")));
6584 }
6585 InlineGenResult::Incomplete { code } => {
6586 let name_str = self.interner.get(name);
6587 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {} - inline function", name_str)?;
6588 for line in code.lines() {
6589 writeln!(self.writer, "// {}", line)?;
6590 }
6591 writeln!(self.writer)?;
6592 self.report.record_skip(name_str, "CODEGEN_INCOMPLETE: type inference incomplete");
6593 self.stats.inline_fns_type_incomplete += 1;
6594 }
6595 InlineGenResult::Success { code, used_libc } => {
6596 if self.successfully_generated_inlines.contains(&name) {
6597 write!(self.writer, "{}", code)?;
6599 self.used_libc_fns.extend(used_libc.iter().cloned());
6600 self.report.record_emit(self.interner.get(name));
6601 self.stats.inline_fns_success += 1;
6602 } else {
6603 let name_str = self.interner.get(name);
6605 let mut unavailable: Vec<String> = result.inline_fn_dict.get_called_functions(name)
6606 .map(|calls| calls.iter()
6607 .filter(|c| inline_set.contains(c) && !self.successfully_generated_inlines.contains(c))
6608 .map(|c| self.interner.get(*c).to_string())
6609 .collect())
6610 .unwrap_or_default();
6611 unavailable.sort(); writeln!(self.writer, "// [CASCADE_UNAVAILABLE] {} - dependency not generated: {}",
6613 name_str, unavailable.join(", "))?;
6614 for line in code.lines() {
6615 writeln!(self.writer, "// {}", line)?;
6616 }
6617 writeln!(self.writer)?;
6618 self.report.record_skip(name_str, format!(
6619 "CASCADE_UNAVAILABLE: dependency not generated: {}",
6620 unavailable.join(", ")));
6621 self.stats.inline_fns_cascade_unavailable += 1;
6622 }
6623 }
6624 }
6625 }
6626
6627 writeln!(self.writer)?;
6628 Ok(())
6629 }
6630
6631 pub fn generate_macros(&mut self, result: &InferResult, known_symbols: &KnownSymbols) -> io::Result<()> {
6633 writeln!(self.writer, "// =============================================================================")?;
6634 writeln!(self.writer, "// Macro Functions")?;
6635 writeln!(self.writer, "// =============================================================================")?;
6636 writeln!(self.writer)?;
6637
6638 let macros: Vec<_> = result.infer_ctx.macros.iter()
6640 .filter(|(_, info)| self.should_include_macro(info))
6641 .collect();
6642 let included_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6643
6644 let sorted_names = self.topological_sort_macros(¯os);
6646
6647 let mut callee_const_params: HashMap<InternedStr, HashSet<usize>> = HashMap::new();
6651 let mut bool_return_macros: HashSet<InternedStr> = HashSet::new();
6652 for (&name, info) in &result.infer_ctx.macros {
6653 if !info.const_pointer_positions.is_empty() {
6654 callee_const_params.insert(name, info.const_pointer_positions.clone());
6655 }
6656 if info.is_bool_return {
6657 bool_return_macros.insert(name);
6658 }
6659 }
6660 self.const_pointer_params = callee_const_params;
6661 self.bool_return_macros = bool_return_macros;
6662
6663 let mut successfully_generated: HashSet<InternedStr> = HashSet::new();
6665
6666 for name in sorted_names {
6667 let info = result.infer_ctx.macros.get(&name).unwrap();
6668
6669 if info.apidoc_suppressed {
6673 let name_str_for_patch = self.interner.get(name);
6674 let reason = result.apidoc_patches.skip_reason(name_str_for_patch)
6675 .unwrap_or("apidoc skip_codegen");
6676 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6677 writeln!(self.writer,
6678 "// [CODEGEN_SUPPRESSED] {}{} - macro function (apidoc patch)",
6679 name_str_for_patch, thx_info)?;
6680 writeln!(self.writer, "// Reason: {}", reason)?;
6681 writeln!(self.writer)?;
6682 self.report.record_skip(name_str_for_patch, format!(
6683 "CODEGEN_SUPPRESSED (apidoc patch): {}", reason));
6684 continue;
6685 }
6686
6687 if info.pair_return {
6690 let name_str = self.interner.get(name);
6691 writeln!(self.writer,
6692 "// [CODEGEN_SUPPRESSED] {} - pair return type (comma expression)",
6693 name_str)?;
6694 writeln!(self.writer,
6695 "// Reason: apidoc declares return type `pair`; \
6696 not representable as a single-value Rust fn")?;
6697 writeln!(self.writer)?;
6698 self.report.record_skip(name_str,
6699 "CODEGEN_SUPPRESSED (pair return type)".to_string());
6700 continue;
6701 }
6702
6703 let unavailable_deps: Vec<String> = info.called_functions.iter()
6709 .filter(|called| {
6710 if included_set.contains(called) {
6712 return result.infer_ctx.macros.get(called)
6713 .map(|u| u.is_parseable() && !u.is_unavailable_for_codegen())
6714 .unwrap_or(false)
6715 && !successfully_generated.contains(called);
6716 }
6717 if result.inline_fn_dict.get(**called)
6719 .map(|f| f.is_target)
6720 .unwrap_or(false)
6721 {
6722 return !self.successfully_generated_inlines.contains(called);
6723 }
6724 false
6725 })
6726 .map(|called| self.interner.get(*called).to_string())
6727 .collect();
6728
6729 if !unavailable_deps.is_empty() {
6730 self.generate_macro_cascade_unavailable(info, &unavailable_deps)?;
6731 self.stats.macros_cascade_unavailable += 1;
6732 continue;
6733 }
6734
6735 let status = self.get_macro_status(info);
6737 match status {
6738 GenerateStatus::Success => {
6739 let const_positions = self.const_pointer_params.get(&name)
6741 .cloned().unwrap_or_default();
6742 let is_bool = self.bool_return_macros.contains(&name);
6743 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))
6744 .with_perl_threaded(self.perl_threaded)
6745 .with_dump_ast_for(self.config.dump_ast_for.clone())
6746 .with_dump_types_for(self.config.dump_types_for.clone())
6747 .with_fields_dict(&result.fields_dict)
6748 .with_const_pointer_positions(const_positions)
6749 .with_bool_return(is_bool, self.bool_return_macros.clone());
6750 let generated = codegen.generate_macro(info);
6751
6752 if generated.has_unresolved_names() {
6753 let name_str = self.interner.get(info.name);
6755 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6756 writeln!(self.writer, "// [UNRESOLVED_NAMES] {}{} - macro function", name_str, thx_info)?;
6757 writeln!(self.writer, "// Unresolved: {}", generated.unresolved_names.join(", "))?;
6758 for line in generated.code.lines() {
6759 writeln!(self.writer, "// {}", line)?;
6760 }
6761 writeln!(self.writer)?;
6762 self.report.record_skip(name_str, format!(
6763 "UNRESOLVED_NAMES: {}", generated.unresolved_names.join(", ")));
6764 self.stats.macros_unresolved_names += 1;
6765 } else if !generated.codegen_errors.is_empty() {
6766 let name_str = self.interner.get(info.name);
6768 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6769 writeln!(self.writer, "// [CODEGEN_ERROR] {}{} - macro function", name_str, thx_info)?;
6770 for err in &generated.codegen_errors {
6771 writeln!(self.writer, "// {}", err)?;
6772 }
6773 for line in generated.code.lines() {
6774 writeln!(self.writer, "// {}", line)?;
6775 }
6776 writeln!(self.writer)?;
6777 self.report.record_skip(name_str, format!(
6778 "CODEGEN_ERROR: {}", generated.codegen_errors.join("; ")));
6779 } else if generated.is_complete() {
6780 write!(self.writer, "{}", generated.code)?;
6782 self.used_libc_fns.extend(generated.used_libc_fns.iter().cloned());
6783 self.report.record_emit(self.interner.get(info.name));
6784 self.stats.macros_success += 1;
6785 successfully_generated.insert(name);
6786 } else {
6787 let name_str = self.interner.get(info.name);
6789 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6790 writeln!(self.writer, "// [CODEGEN_INCOMPLETE] {}{} - macro function", name_str, thx_info)?;
6791 for line in generated.code.lines() {
6792 writeln!(self.writer, "// {}", line)?;
6793 }
6794 writeln!(self.writer)?;
6795 self.report.record_skip(name_str, "CODEGEN_INCOMPLETE: type inference incomplete");
6796 self.stats.macros_type_incomplete += 1;
6797 }
6798 }
6799 GenerateStatus::ParseFailed => {
6800 self.generate_macro_parse_failed(info)?;
6801 self.report.record_skip(self.interner.get(info.name),
6802 "PARSE_FAILED: macro body does not parse");
6803 self.stats.macros_parse_failed += 1;
6804 }
6805 GenerateStatus::TypeIncomplete => {
6806 self.generate_macro_type_incomplete(info, result)?;
6807 self.report.record_skip(self.interner.get(info.name),
6808 "TYPE_INCOMPLETE: parameter/return type could not be inferred");
6809 self.stats.macros_type_incomplete += 1;
6810 }
6811 GenerateStatus::CallsUnavailable => {
6812 let absent: Vec<&str> = info.called_functions.iter()
6816 .filter(|fn_id| {
6817 let fn_name = self.interner.get(**fn_id);
6818 !self.is_function_available(**fn_id, fn_name, result)
6819 })
6820 .map(|fn_id| self.interner.get(*fn_id))
6821 .collect();
6822 if absent.is_empty() {
6823 let cascade_deps: Vec<String> = info.called_functions.iter()
6825 .filter(|fn_id| {
6826 if let Some(m) = result.infer_ctx.macros.get(*fn_id) {
6827 return m.is_unavailable_for_codegen();
6828 }
6829 if result.inline_fn_dict.get(**fn_id).is_some() {
6830 return result.inline_fn_dict
6831 .is_unavailable_for_codegen(**fn_id);
6832 }
6833 false
6834 })
6835 .map(|fn_id| self.interner.get(*fn_id).to_string())
6836 .collect();
6837 self.generate_macro_cascade_unavailable(info, &cascade_deps)?;
6838 self.stats.macros_cascade_unavailable += 1;
6839 } else {
6840 let mut absent_sorted: Vec<String> =
6841 absent.iter().map(|s| s.to_string()).collect();
6842 absent_sorted.sort();
6843 self.generate_macro_calls_unavailable(info, result)?;
6844 self.report.record_skip(self.interner.get(info.name), format!(
6845 "CALLS_UNAVAILABLE: calls unavailable function(s): {}",
6846 absent_sorted.join(", ")));
6847 self.stats.macros_calls_unavailable += 1;
6848 }
6849 }
6850 GenerateStatus::ContainsGoto => {
6851 let name_str = self.interner.get(info.name);
6852 writeln!(self.writer, "// [CONTAINS_GOTO] {} - excluded (contains goto)", name_str)?;
6853 writeln!(self.writer)?;
6854 self.report.record_skip(name_str, "CONTAINS_GOTO: excluded (contains goto)");
6855 }
6856 GenerateStatus::GenericUnsupported => {
6857 let name_str = self.interner.get(info.name);
6858 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6859 writeln!(self.writer, "// [GENERIC_UNSUPPORTED] {}{} - Rust cannot cast to generic type T", name_str, thx_info)?;
6860 let const_positions = self.const_pointer_params.get(&name)
6862 .cloned().unwrap_or_default();
6863 let is_bool = self.bool_return_macros.contains(&name);
6864 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))
6865 .with_perl_threaded(self.perl_threaded)
6866 .with_fields_dict(&result.fields_dict)
6867 .with_const_pointer_positions(const_positions)
6868 .with_bool_return(is_bool, self.bool_return_macros.clone());
6869 let generated = codegen.generate_macro(info);
6870 for line in generated.code.lines() {
6871 writeln!(self.writer, "// {}", line)?;
6872 }
6873 writeln!(self.writer)?;
6874 self.report.record_skip(self.interner.get(info.name),
6875 "GENERIC_UNSUPPORTED: Rust cannot cast to generic type T");
6876 self.stats.macros_generic_unsupported += 1;
6877 }
6878 GenerateStatus::Skip => {
6879 self.report.record_skip(self.interner.get(info.name),
6881 "SKIP: excluded from code generation");
6882 }
6883 }
6884 }
6885
6886 Ok(())
6887 }
6888
6889 fn topological_sort_macros(
6893 &self,
6894 macros: &[(&InternedStr, &MacroInferInfo)],
6895 ) -> Vec<InternedStr> {
6896 use std::collections::VecDeque;
6897
6898 let macro_set: HashSet<InternedStr> = macros.iter().map(|(n, _)| **n).collect();
6899
6900 let mut in_degree: HashMap<InternedStr, usize> = HashMap::new();
6902 let mut dependents: HashMap<InternedStr, Vec<InternedStr>> = HashMap::new();
6903
6904 for (name, _) in macros {
6905 in_degree.insert(**name, 0);
6906 }
6907
6908 for (name, info) in macros {
6909 for used in &info.uses {
6910 if macro_set.contains(used) {
6911 *in_degree.entry(**name).or_insert(0) += 1;
6913 dependents.entry(*used).or_default().push(**name);
6914 }
6915 }
6916 }
6917
6918 let mut queue: VecDeque<InternedStr> = {
6920 let mut zeros: Vec<_> = in_degree.iter()
6921 .filter(|(_, deg)| **deg == 0)
6922 .map(|(name, _)| *name)
6923 .collect();
6924 zeros.sort_by_key(|n| self.interner.get(*n));
6925 zeros.into_iter().collect()
6926 };
6927
6928 let mut result = Vec::with_capacity(macros.len());
6929
6930 while let Some(name) = queue.pop_front() {
6931 result.push(name);
6932 if let Some(deps) = dependents.get(&name) {
6933 let mut newly_ready: Vec<InternedStr> = Vec::new();
6935 for dep in deps {
6936 if let Some(deg) = in_degree.get_mut(dep) {
6937 *deg -= 1;
6938 if *deg == 0 {
6939 newly_ready.push(*dep);
6940 }
6941 }
6942 }
6943 newly_ready.sort_by_key(|n| self.interner.get(*n));
6945 for n in newly_ready {
6946 queue.push_back(n);
6947 }
6948 }
6949 }
6950
6951 if result.len() < macros.len() {
6953 let result_set: HashSet<_> = result.iter().copied().collect();
6954 let mut remaining: Vec<_> = macro_set.iter()
6955 .filter(|n| !result_set.contains(n))
6956 .copied()
6957 .collect();
6958 remaining.sort_by_key(|n| self.interner.get(*n));
6959 result.extend(remaining);
6960 }
6961
6962 result
6963 }
6964
6965 fn generate_macro_cascade_unavailable(
6967 &mut self,
6968 info: &MacroInferInfo,
6969 unavailable_deps: &[String],
6970 ) -> io::Result<()> {
6971 let name_str = self.interner.get(info.name);
6972 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
6973 let mut deps: Vec<&String> = unavailable_deps.iter().collect();
6974 deps.sort(); let deps: Vec<&str> = deps.iter().map(|s| s.as_str()).collect();
6976 writeln!(self.writer,
6977 "// [CASCADE_UNAVAILABLE] {}{} - dependency not generated: {}",
6978 name_str, thx_info, deps.join(", "))?;
6979 writeln!(self.writer)?;
6980 self.report.record_skip(name_str, format!(
6981 "CASCADE_UNAVAILABLE: dependency not generated: {}", deps.join(", ")));
6982 Ok(())
6983 }
6984
6985 fn should_include_macro(&self, info: &MacroInferInfo) -> bool {
6987 if !info.is_target {
6989 return false;
6990 }
6991
6992 if !info.has_body {
6994 return false;
6995 }
6996
6997 info.is_function
6999 }
7000
7001 fn get_macro_status(&self, info: &MacroInferInfo) -> GenerateStatus {
7003 if info.calls_unavailable {
7005 return GenerateStatus::CallsUnavailable;
7006 }
7007
7008 if !info.generic_type_params.is_empty() {
7011 return GenerateStatus::GenericUnsupported;
7012 }
7013
7014 match &info.parse_result {
7015 ParseResult::Unparseable(_) => GenerateStatus::ParseFailed,
7016 ParseResult::Statement(items) => {
7017 if block_items_contain_goto(items) {
7019 return GenerateStatus::ContainsGoto;
7020 }
7021 if info.is_fully_confirmed() {
7022 GenerateStatus::Success
7023 } else {
7024 GenerateStatus::TypeIncomplete
7025 }
7026 }
7027 ParseResult::Expression(_) => {
7028 if info.is_fully_confirmed() {
7029 GenerateStatus::Success
7030 } else {
7031 GenerateStatus::TypeIncomplete
7032 }
7033 }
7034 }
7035 }
7036
7037 fn generate_macro_parse_failed(&mut self, info: &MacroInferInfo) -> io::Result<()> {
7039 let name_str = self.interner.get(info.name);
7040
7041 let params_str = if info.is_function {
7043 let params: Vec<_> = info.params.iter()
7044 .map(|p| self.interner.get(p.name).to_string())
7045 .collect();
7046 format!("({})", params.join(", "))
7047 } else {
7048 String::new()
7049 };
7050
7051 writeln!(self.writer, "// [PARSE_FAILED] {}{}", name_str, params_str)?;
7052
7053 if let ParseResult::Unparseable(Some(err_msg)) = &info.parse_result {
7055 writeln!(self.writer, "// Error: {}", err_msg)?;
7056 }
7057
7058 writeln!(self.writer, "// (tokens not available in parsed form)")?;
7060 writeln!(self.writer)?;
7061
7062 Ok(())
7063 }
7064
7065 fn generate_macro_calls_unavailable(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7067 let name_str = self.interner.get(info.name);
7068
7069 let params_str = if info.is_function {
7071 let params: Vec<_> = info.params.iter()
7072 .map(|p| self.interner.get(p.name).to_string())
7073 .collect();
7074 format!("({})", params.join(", "))
7075 } else {
7076 String::new()
7077 };
7078
7079 let thx_info = if info.is_thx_dependent { " [THX]" } else { "" };
7081
7082 writeln!(self.writer, "// [CALLS_UNAVAILABLE] {}{}{} - calls unavailable function(s)", name_str, params_str, thx_info)?;
7083
7084 let unavailable_fns: Vec<_> = info.called_functions.iter()
7086 .filter(|&fn_id| {
7087 let fn_name = self.interner.get(*fn_id);
7088 !self.is_function_available(*fn_id, fn_name, result)
7090 })
7091 .map(|fn_id| self.interner.get(*fn_id))
7092 .collect();
7093
7094 if !unavailable_fns.is_empty() {
7095 let mut unavailable_fns = unavailable_fns;
7096 unavailable_fns.sort(); writeln!(self.writer, "// Unavailable: {}", unavailable_fns.join(", "))?;
7098 }
7099
7100 writeln!(self.writer)?;
7101
7102 Ok(())
7103 }
7104
7105 fn is_function_available(&self, fn_id: crate::InternedStr, fn_name: &str, result: &InferResult) -> bool {
7107 if result.infer_ctx.macros.contains_key(&fn_id) {
7109 return true;
7110 }
7111
7112 if let Some(rust_decl_dict) = &result.rust_decl_dict {
7114 if rust_decl_dict.fns.contains_key(fn_name) {
7115 return true;
7116 }
7117 }
7118
7119 if result.inline_fn_dict.get(fn_id).is_some() {
7121 return true;
7122 }
7123
7124 let builtin_fns = [
7126 "__builtin_expect",
7127 "__builtin_offsetof",
7128 "offsetof",
7129 "__builtin_types_compatible_p",
7130 "__builtin_constant_p",
7131 "__builtin_choose_expr",
7132 "__builtin_unreachable",
7133 "__builtin_trap",
7134 "__builtin_assume",
7135 "__builtin_bswap16",
7136 "__builtin_bswap32",
7137 "__builtin_bswap64",
7138 "__builtin_popcount",
7139 "__builtin_clz",
7140 "__builtin_ctz",
7141 "pthread_mutex_lock",
7142 "pthread_mutex_unlock",
7143 "pthread_rwlock_rdlock",
7144 "pthread_rwlock_wrlock",
7145 "pthread_rwlock_unlock",
7146 "memchr",
7147 "memcpy",
7148 "memmove",
7149 "memset",
7150 "strlen",
7151 "strcmp",
7152 "strncmp",
7153 "strcpy",
7154 "strncpy",
7155 "ASSERT_IS_LITERAL",
7156 "ASSERT_IS_PTR",
7157 "ASSERT_NOT_PTR",
7158 ];
7159
7160 if builtin_fns.contains(&fn_name) {
7161 return true;
7162 }
7163
7164 false
7165 }
7166
7167 fn generate_macro_type_incomplete(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7169 let name_str = self.interner.get(info.name);
7170
7171 let params_str = if info.is_function {
7173 let params: Vec<_> = info.params.iter()
7174 .map(|p| self.interner.get(p.name).to_string())
7175 .collect();
7176 format!("({})", params.join(", "))
7177 } else {
7178 String::new()
7179 };
7180
7181 writeln!(self.writer, "// [TYPE_INCOMPLETE] {}{}", name_str, params_str)?;
7182
7183 writeln!(self.writer, "// Args status: {:?}, Return status: {:?}",
7185 info.args_infer_status, info.return_infer_status)?;
7186
7187 writeln!(self.writer, "// Typed S-expression:")?;
7189 self.write_typed_sexp_comment(info, result)?;
7190
7191 writeln!(self.writer)?;
7192 Ok(())
7193 }
7194
7195 fn write_typed_sexp_comment(&mut self, info: &MacroInferInfo, _result: &InferResult) -> io::Result<()> {
7197 match &info.parse_result {
7198 ParseResult::Expression(expr) => {
7199 self.write_expr_sexp_comment(expr, info, "// ")?;
7200 }
7201 ParseResult::Statement(block_items) => {
7202 for item in block_items {
7203 if let BlockItem::Stmt(stmt) = item {
7204 self.write_stmt_sexp_comment(stmt, info, "// ")?;
7205 }
7206 }
7207 }
7208 ParseResult::Unparseable(_) => {
7209 writeln!(self.writer, "// (unparseable)")?;
7210 }
7211 }
7212 Ok(())
7213 }
7214
7215 fn write_expr_sexp_comment(&mut self, expr: &Expr, info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7217 let mut buf = Vec::new();
7219 {
7220 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7221 let _ = printer.print_expr(expr);
7222 }
7223
7224 let sexp_str = String::from_utf8_lossy(&buf);
7226 let type_info = self.get_expr_type_info(expr, info);
7227
7228 for line in sexp_str.lines() {
7230 writeln!(self.writer, "{}{}", prefix, line)?;
7231 }
7232 if !type_info.is_empty() {
7233 writeln!(self.writer, "{} :type {}", prefix, type_info)?;
7234 }
7235
7236 Ok(())
7237 }
7238
7239 fn write_stmt_sexp_comment(&mut self, stmt: &Stmt, _info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7241 let mut buf = Vec::new();
7242 {
7243 let mut printer = SexpPrinter::new(&mut buf, self.interner);
7244 let _ = printer.print_stmt(stmt);
7245 }
7246
7247 let sexp_str = String::from_utf8_lossy(&buf);
7248 for line in sexp_str.lines() {
7249 writeln!(self.writer, "{}{}", prefix, line)?;
7250 }
7251
7252 Ok(())
7253 }
7254
7255 fn get_expr_type_info(&self, expr: &Expr, info: &MacroInferInfo) -> String {
7257 if let Some(constraints) = info.type_env.expr_constraints.get(&expr.id) {
7259 if let Some(first) = constraints.first() {
7260 return first.ty.to_display_string(self.interner);
7261 }
7262 }
7263 "<unknown>".to_string()
7264 }
7265}
7266
7267#[cfg(test)]
7268mod codegen_report_tests {
7269 use super::*;
7270
7271 fn sample_report() -> CodegenReport {
7272 let mut report = CodegenReport::default();
7273 report.record_emit("CvFILE");
7274 report.record_emit("CvROOT");
7275 report.record_skip("CvSTART", "CASCADE_UNAVAILABLE: dependency not generated: CvROOT");
7276 report
7277 }
7278
7279 #[test]
7280 fn test_check_required_empty_list_is_noop() {
7281 let report = sample_report();
7282 assert!(report.check_required(&[]).is_ok());
7283 }
7284
7285 #[test]
7286 fn test_check_required_emitted_names_pass() {
7287 let report = sample_report();
7288 let required = vec!["CvFILE".to_string(), "CvROOT".to_string()];
7289 assert!(report.check_required(&required).is_ok());
7290 }
7291
7292 #[test]
7293 fn test_check_required_skipped_name_reports_recorded_reason() {
7294 let report = sample_report();
7295 let required = vec!["CvSTART".to_string()];
7296 let err = report.check_required(&required).unwrap_err();
7297 assert_eq!(err.violations.len(), 1);
7298 assert_eq!(err.violations[0].name, "CvSTART");
7299 assert!(err.violations[0].reason.contains("CASCADE_UNAVAILABLE"));
7300 let msg = err.to_string();
7302 assert!(msg.contains("CvSTART"));
7303 assert!(msg.contains("CASCADE_UNAVAILABLE"));
7304 }
7305
7306 #[test]
7307 fn test_check_required_unknown_name_reports_not_a_target() {
7308 let report = sample_report();
7309 let required = vec!["NoSuchFunction".to_string()];
7310 let err = report.check_required(&required).unwrap_err();
7311 assert_eq!(err.violations.len(), 1);
7312 assert!(err.violations[0].reason.contains("not a codegen target"));
7313 }
7314
7315 #[test]
7316 fn test_check_required_collects_all_violations() {
7317 let report = sample_report();
7318 let required = vec![
7319 "CvFILE".to_string(), "CvSTART".to_string(), "NoSuchFunction".to_string(), ];
7323 let err = report.check_required(&required).unwrap_err();
7324 assert_eq!(err.violations.len(), 2);
7325 }
7326}