Skip to main content

libperl_macrogen/
rust_codegen.rs

1//! Rust コード生成モジュール
2//!
3//! 型推論結果から Rust コードを生成する。
4
5use 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/// bindings.rs から抽出した codegen 用情報
21#[derive(Debug, Default, Clone)]
22pub struct BindingsInfo {
23    /// 配列型の extern static 変数名の集合
24    pub static_arrays: HashSet<String>,
25    /// extern static 変数名 → 型文字列("[T; N]" や "T" 等)
26    /// 配列の要素型抽出に使う。`static_array_element_type` も参照。
27    pub static_types: HashMap<String, String>,
28    /// ビットフィールドのメソッド名集合(構造体名 → メソッド名セット)
29    pub bitfield_methods: HashMap<String, HashSet<String>>,
30}
31
32impl BindingsInfo {
33    /// RustDeclDict から BindingsInfo を構築
34    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    /// `static_arrays` に含まれる名前の **配列要素型** を返す。
43    /// `static_types[name]` が `"[T; N]"` 形式なら T を取り出す。
44    /// 抽出できなかったら None(呼出側でフォールバック)。
45    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
55/// libc crate から提供される関数名のリスト
56/// codegen がそのまま関数呼び出しとして出力する関数のみ
57/// (`__builtin_expect` 等の codegen 変換済み関数は含めない)
58const LIBC_FUNCTIONS: &[&str] = &[
59    "strcmp", "strlen", "strncmp", "strcpy", "strncpy",
60    "memset", "memchr", "memcpy", "memmove",
61];
62
63/// 既知の libc 関数の引数型 (bindings.rs に登録されない関数を補完)。
64///
65/// 呼出側は `as *mut c_char` で渡しがちだが libc は `*mut c_void` を要求する。
66/// ハードコードした型を `get_callee_param_type_extended` 経由で引くと、
67/// 自動 as-cast (cast_arg_syn_if_needed の void-pointer 分岐) に乗る。
68fn libc_fn_param_type(func_name: &str, arg_index: usize) -> Option<UnifiedType> {
69    match (func_name, arg_index) {
70        // memset(void *s, int c, size_t n)
71        ("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(void *dest, const void *src, size_t n)
75        ("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(const void *s, int c, size_t n)
79        ("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(const void *s1, const void *s2, size_t n)
83        ("memcmp", 0) | ("memcmp", 1) => Some(UnifiedType::from_rust_str("*const c_void")),
84        ("memcmp", 2) => Some(UnifiedType::from_rust_str("usize")),
85        // strcmp / strncmp: *const c_char
86        ("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: *const c_char
90        ("strlen", 0) => Some(UnifiedType::from_rust_str("*const c_char")),
91        // strcpy/strncpy: dest *mut, src *const c_char
92        ("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
99/// コード生成時に解決可能なシンボルの集合
100///
101/// bindings.rs、マクロ辞書、inline 関数辞書、ビルトイン関数等から
102/// 既知のシンボル名を収集する。コード生成時に `ExprKind::Ident` が
103/// この集合に含まれない場合、未解決シンボルとして検出する。
104pub struct KnownSymbols {
105    names: HashSet<String>,
106}
107
108impl KnownSymbols {
109    /// InferResult から既知シンボル集合を構築
110    pub fn new(result: &InferResult, interner: &StringInterner) -> Self {
111        let mut names = HashSet::new();
112
113        // bindings.rs の関数名
114        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        // マクロ名(関数呼び出しとして保持されるもの)
139        for (name_id, info) in &result.infer_ctx.macros {
140            let name_str = interner.get(*name_id);
141            // 関数マクロのみ既知とする(オブジェクトマクロは除外)
142            // オブジェクトマクロ名(例: `n`, `s`, `c`)を登録すると、
143            // ジェネリック誤検出で残ったパラメータ参照が既知扱いになってしまう
144            if info.has_body && info.is_function {
145                names.insert(name_str.to_string());
146            }
147        }
148
149        // inline 関数名
150        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        // ビルトイン関数(codegen が変換・除去するもの)
156        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        // libc 関数(use libc::{...} で利用可能になる)
190        for name in LIBC_FUNCTIONS {
191            names.insert(name.to_string());
192        }
193
194        // 自動生成 static const 配列名(`static_array_emitter.rs` 由来)
195        // 注: struct/typedef alias 名は `generate()` 側で実際に出力できた名前のみ
196        // 後から `insert()` する。事前にここで全部入れると未生成の型を参照する
197        // コードを「既知」とみなして compile error を起こす可能性がある。
198        for (name_id, _) in result.global_const_dict.iter() {
199            names.insert(interner.get(*name_id).to_string());
200        }
201
202        // Rust プリミティブ / 標準識別子
203        let rust_primitives = [
204            "true", "false", "std", "crate", "self", "super",
205            "null_mut", "null",
206            "PerlInterpreter", "my_perl",
207            // 出力ヘッダで `type X = Y;` 定義しているもの
208            // (`generate_use_statements` 参照)
209            "size_t", "ssize_t", "SSize_t",
210            // std::ffi 由来(use 文で import 済み)
211            "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    /// シンボル名が既知かどうかチェック
222    fn contains(&self, name: &str) -> bool {
223        self.names.contains(name)
224    }
225
226    /// 既知シンボルとして名前を追加
227    pub fn insert(&mut self, name: String) {
228        self.names.insert(name);
229    }
230}
231
232/// Rust の予約語リスト(strict keywords + reserved keywords)
233/// 注: true/false はリテラルなので含めない
234const RUST_KEYWORDS: &[&str] = &[
235    // Strict keywords (true/false は除外 - リテラルなのでエスケープ不要)
236    "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    // Reserved keywords
242    "abstract", "become", "box", "do", "final", "gen", "macro", "override",
243    "priv", "try", "typeof", "unsized", "virtual", "yield",
244];
245
246/// 識別子を Rust コードに変換
247///
248/// - Rust の予約語は r# を付ける
249/// - C のプリプロセッサマクロは Rust の同等品に変換
250fn escape_rust_keyword(name: &str) -> String {
251    match name {
252        // C プリプロセッサマクロ → Rust マクロ
253        "__FILE__" => "file!()".to_string(),
254        "__LINE__" => "line!()".to_string(),
255        // Rust 予約語はエスケープ
256        _ if RUST_KEYWORDS.contains(&name) => format!("r#{}", name),
257        // その他はそのまま
258        _ => name.to_string(),
259    }
260}
261
262/// 単語境界を考慮した文字列置換
263///
264/// 型パラメータ名の置換時に、部分文字列一致を避けるために使用。
265/// 例: "XV" を "T" に置換するとき、"XPVNV" は変更しない。
266fn 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        // 前方の境界チェック
277        let before_ok = abs_pos == 0 || !is_ident_char(bytes[abs_pos - 1]);
278        // 後方の境界チェック
279        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
295/// 識別子を構成する文字かどうか
296fn is_ident_char(b: u8) -> bool {
297    b.is_ascii_alphanumeric() || b == b'_'
298}
299
300/// 二項演算子を Rust 形式に変換
301fn 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
324/// 代入演算子を Rust 形式に変換
325fn 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
341/// 文字をエスケープ
342fn 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
354/// 文字列をエスケープ
355fn escape_string(s: &[u8]) -> String {
356    s.iter().map(|&c| escape_char(c)).collect()
357}
358
359/// C の `(void)` 単独パラメータ = 引数なし、を判定する。
360///
361/// K&R 方式との互換のため、C では明示的に `void` を単一パラメータとして
362/// 書くことで「引数なし」を宣言する慣習がある (例: `int foo(void)`)。
363/// Rust には対応する概念がなく、そのまま `_: ()` に訳すと呼出側との
364/// 食い違いが起きるため、**パラメータなし** として生成する。
365fn is_void_only_param_list(params: &[ParamDecl]) -> bool {
366    if params.len() != 1 {
367        return false;
368    }
369    let p = &params[0];
370    // 名前付きでない(無名引数)こと、ポインタ派生していないこと、
371    // かつ単独の TypeSpec::Void であること。
372    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
381/// 式がゼロ定数かどうかを判定
382fn 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
390/// 式が bool として扱える形式かどうかを判定
391///
392/// キャスト `(expr as bool)` を含む場合も true を返す
393pub 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        // (expr as bool) も bool を返す
400        ExprKind::Cast { type_name, .. } => {
401            // TypeSpec が Bool かチェック
402            type_name.specs.type_specs.iter().any(|ts| {
403                matches!(ts, TypeSpec::Bool)
404            })
405        }
406        // LogNot は常に bool を返す(if 式として生成される)
407        ExprKind::LogNot(_) => true,
408        // 三項演算子: 両 arm が bool なら全体も bool。
409        // <=5.34 の cBOOL は `((c) ? (bool)1 : (bool)0)` で、arm は
410        // (bool) キャストにより bool として生成される。ここで ternary を
411        // 非 bool と誤分類すると外側に更に `!= 0` が付き、Rust では
412        // `bool != {integer}` (E0308) になる (5.36+ は cBOOL が
413        // `((bool)(c))` の単純キャストになったため露出しない)
414        ExprKind::Conditional { then_expr, else_expr, .. } => {
415            is_boolean_expr(then_expr) && is_boolean_expr(else_expr)
416        }
417        _ => false,
418    }
419}
420
421
422/// is_boolean_expr の再帰版: __builtin_expect(cond, val) を透過する
423fn 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        // Cast to bool: 内側が bool なら全体も bool
436        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
447/// コンテキスト付き bool 式判定: 呼び出し先マクロ/外部関数の戻り値型も考慮
448pub 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
472/// TypeRepr がポインタ型かどうか判定
473fn 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
490/// 自家生成マクロの param に対する全制約のうち、Tier が最も高い
491/// (=数値が小さい) 非 void TypeRepr のクローンを返す。
492/// `param.expr_id()` および `param_to_exprs` から得た全 ExprId を走査する。
493fn 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    // param_constraints (マクロ自身の apidoc パラメータ宣言など) を先に走査する:
500    // tier 同点のとき「自身の宣言」が「呼び出し先由来の制約」に勝つように
501    // (厳密未満 `<` の比較なので先着が優先される)。
502    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(&param.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
534/// `Expr` を再帰的に走査し、`ExprKind::Ident(name)` のうち `subs` に
535/// マッチするものを `subs[name]` のクローンで置換する。
536///
537/// 用途: 自家生成マクロの本体式に対し、`(param_name → arg_expr)` の
538/// 対応で alpha 置換を行う(C プリプロセッサの token 置換相当)。
539/// `&MACRO(args)` を `&<inlined_body>` に展開するために使う。
540fn 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        // StmtExpr 内部は文を含むので alpha 置換は当面非対応(保守的)
613        ExprKind::StmtExpr(_) => {}
614    }
615}
616
617/// 式が「文の位置で値を捨てると `-D warnings` を踏む」形をしているか判定する。
618/// 主な用途: C カンマ `(A, B)` の LHS を `let _ = A;` で包むかの判定。
619///
620/// 該当パターン(wrap が必要):
621/// - trailing-expr 付き block (`{ stmt; expr }`): `unused unary / logical op` の温床
622/// - 論理演算 `&&` / `||` (`unused logical operation`)
623/// - 単項式 `*p` `-x` `!b` 等 (`unused unary operation`)
624///
625/// 該当しないパターン(wrap 不要):
626/// - 関数呼出 / メソッド呼出: 大半の FFI 関数は `()` を返し must_use ではない。
627///   `must_use` 戻り値(`size_of_val` 等)は `(void)cast` 経路で別途処理される
628/// - assert!() や `{ stmt; }` のように `()` を返すと明らかなもの
629/// - 単純な代入 `x = y` (Rust では `()` 型)
630fn 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        // パーレン内は中身を見る(`(a || b)` 等)
641        syn::Expr::Paren(p) => expr_yields_value_for_stmt_use(&p.expr),
642        _ => false,
643    }
644}
645
646/// unsigned 型へのキャスト式かどうか判定
647/// 例: "(x as usize)", "(x as u32)"
648fn 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
657/// 指定された型名が unsigned 整数型(プリミティブ + 既知エイリアス)か判定。
658/// 真なら `{ty}::MAX` のような associated const が使える。
659fn 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
669/// 式文字列の最外レベルの不要な括弧を除去する。
670/// "(expr)" → "expr" (先頭の '(' と末尾の ')' が対応する場合のみ)
671/// ただしブロック式 "({...})" は除去しない( `{...} op expr` が構文エラーになるため)
672fn 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    // 先頭の '(' と末尾の ')' が対応するかチェック
678    let inner = &s[1..s.len() - 1];
679    // ブロック式 ({...}) は strip しない
680    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                    // 内部で閉じ括弧が余る → 先頭と末尾は非対応
691                    return s;
692                }
693            }
694            _ => {}
695        }
696    }
697    if depth == 0 {
698        inner
699    } else {
700        s
701    }
702}
703
704/// 式が NULL リテラル(整数 0 または (void*)0 のような Cast)かどうか判定
705/// assert(expr || !"message") パターンの RHS からメッセージ文字列を抽出
706fn 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
715/// assert 条件が `real_cond || !"message"` パターンかどうかを分解する
716fn 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
725/// Perl の SV サブタイプ(GV, HV, AV, CV, IO 等)から SV へのポインタキャストかどうかを判定
726fn is_sv_subtype_cast(from: &UnifiedType, to: &UnifiedType) -> bool {
727    // inner 型を取得 (Named 以外は "c_void" 扱いにして void ポインタ互換を
728    // 拾う)。`Pointer { inner: Void }` は to_rust_string で c_void になる。
729    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    // SV サブタイプのリスト (bindings.rs の構造体名は小文字版を出すケースが
745    // 多い: `pub type SV = sv;` などの typedef エイリアス関係のため、両方を
746    // 対象にする)
747    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 ↔ サブタイプ(双方向)
753    (SV_SUBTYPES.contains(&from_name.as_str()) && sv_like(&to_name))
754        || (sv_like(&from_name) && SV_SUBTYPES.contains(&to_name.as_str()))
755        // サブタイプ ↔ サブタイプ (GV → CV など)
756        || (SV_SUBTYPES.contains(&from_name.as_str())
757            && SV_SUBTYPES.contains(&to_name.as_str()))
758        // c_void ↔ 任意のポインタ
759        || 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
771/// ポインタ型に対応する null ポインタ式を生成
772fn 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
780/// 型文字列を正規化して整数型なら canonical Rust primitive に変換
781fn 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        // Perl 固有の整数 typedef。Stack_off_t は 5.32+ で I32、それ以前は
795        // IV (i64) 相当だが、bindings.rs の型に合わせて i32 として扱う。
796        "Stack_off_t" => Some("i32"),
797        _ => None,
798    }
799}
800
801/// 64-bit プラットフォームで i64/isize, u64/usize を同一視して比較
802fn 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
810/// 整数型の幅ランク (昇格順序判定用)
811/// returns (is_signed, width_rank)
812fn 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
823/// 二項ビット演算で C の整数昇格に従い広い方の型を返す
824/// 同一正規化型なら None(キャスト不要)
825fn 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        // 同一幅: unsigned が勝つ (C規格 6.3.1.8)
833        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
841/// 2 つのポインタ型の inner が Rust として「同じ型」か判定する
842/// (const/mut は無視)。
843///
844/// `*mut c_char` と `*mut i8`、`*const c_int` と `*const i32` のように、
845/// C 別名と Rust プリミティブの対応関係を吸収する。
846/// 二重ポインタ `**const T` vs `**mut T` にも再帰的に対応する。
847pub 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
853/// `pointer_inner_compatible` の再帰ヘルパ。ポインタ以外の inner も扱える。
854fn type_inner_compatible(a: &UnifiedType, b: &UnifiedType) -> bool {
855    // 両方ポインタなら再帰
856    if a.is_pointer() && b.is_pointer() {
857        return pointer_inner_compatible(a, b);
858    }
859    // 整数型は normalize_integer_type で正規化して比較
860    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    // void は双方で吸収
866    if a.is_void() && b.is_void() { return true; }
867    // それ以外は文字列一致で判定
868    a_s == b_s
869}
870
871/// 両方ポインタで、inner は compatible だが const/mut が違う場合に true。
872pub 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
878/// マクロ本体を走査し、`&mut param` や代入先として使用されるパラメータを検出する
879/// ポインタパラメータが *mut である必要があるかを判定する。
880/// callee_const_params: 呼び出し先マクロで *const に確定したパラメータ情報
881///   key = マクロ名(InternedStr), value = const パラメータの引数位置集合
882pub 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, &param_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, &param_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        // *param = expr, param->field = expr → param must be *mut
962        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        // ++(*param), (*param)++ 等
968        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        // func(param) — 呼び出し先の引数 mutability をチェック
974        ExprKind::Call { func, args } => {
975            // 呼び出し先マクロの const 情報をチェック
976            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                            // 呼び出し先の i 番目が const なら mut 不要
982                            let is_const_at_callee = const_arg_positions
983                                .map_or(false, |positions| positions.contains(&i));
984                            if !is_const_at_callee {
985                                // 呼び出し先が const でない(or 情報なし)→ mut 必要
986                                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        // 再帰
1000        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        // MacroCall(name, args) — 呼び出し先マクロの引数 mutability をチェック
1010        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
1058/// 代入先の式に含まれるパラメータを must-mut としてマークする
1059pub fn mark_lvalue_mut(expr: &Expr, params: &HashSet<InternedStr>, result: &mut HashSet<InternedStr>) {
1060    match &expr.kind {
1061        // *param = ... → param must be *mut
1062        ExprKind::Deref(inner) => {
1063            if let ExprKind::Ident(name) = &inner.kind {
1064                if params.contains(name) {
1065                    result.insert(*name);
1066                }
1067            }
1068            // (*param).field の場合も再帰的にチェック
1069            mark_lvalue_mut(inner, params, result);
1070        }
1071        // param->field = ... → param must be *mut
1072        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        // (*param).field = ... → param must be *mut
1081        ExprKind::Member { expr: inner, .. } => {
1082            mark_lvalue_mut(inner, params, result);
1083        }
1084        // (SomeType*)param → キャスト先が *mut ならパラメータも mut
1085        ExprKind::Cast { expr: inner, type_name } => {
1086            if let ExprKind::Ident(name) = &inner.kind {
1087                if params.contains(name) {
1088                    // キャスト先がポインタで non-const なら mut 必要
1089                    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        // MacroCall(name, expanded) → expanded 形式で lvalue を再帰チェック
1102        ExprKind::MacroCall { expanded, args, .. } => {
1103            mark_lvalue_mut(expanded, params, result);
1104            // 引数にパラメータが直接渡されている場合もチェック
1105            for arg in args {
1106                mark_lvalue_mut(arg, params, result);
1107            }
1108        }
1109        // Call の lvalue 使用: func(param) が lvalue として使われる場合
1110        // マクロ関数の呼び出し結果が lvalue なら、引数パラメータは *mut 必要
1111        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
1125// (旧 collect_mut_params 系は Phase 2 の crate::local_usage へ移設した。
1126//  GH #16/#22/#23 — Pass Separation Rule)
1127
1128/// 構造体フィールド名 → 型の逆引きマップを構築
1129/// 全構造体で同名フィールドの型が一致する場合のみ含む
1130/// 型文字列が関数ポインタ形式(裸 fn または `Option<...fn(...)>`)かを判定する。
1131///
1132/// `quote::ToTokens` 経由の出力は `fn (` のようにスペースが入ることがあるため、
1133/// `fn(` と `fn (` の両方を許容する。
1134fn 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        // bitfield アクセサ getter の戻り値型を統合。
1161        // C ソースの `(*o).op_type` (Member 式)は意味的に「op_type フィールド」
1162        // 相当だが、bindings.rs では bitfield アクセサ getter (`pub fn op_type(&self) -> U16`)
1163        // として現れる。型推論では同名のフィールドアクセスと同じ扱いで OK。
1164        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/// コード生成の設定
1186#[derive(Debug, Clone)]
1187pub struct CodegenConfig {
1188    /// inline 関数を出力するか
1189    pub emit_inline_fns: bool,
1190    /// マクロを出力するか
1191    pub emit_macros: bool,
1192    /// コメントにソース位置を含めるか
1193    pub include_source_location: bool,
1194    /// ヘッダーに出力する use 文
1195    /// 空の場合はデフォルトの use 文を出力
1196    pub use_statements: Vec<String>,
1197    /// AST ダンプ対象関数名(デバッグ用)
1198    pub dump_ast_for: Option<String>,
1199    /// 型推論ダンプ対象関数名(デバッグ用)
1200    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    /// デフォルトの use 文を取得
1218    ///
1219    /// 生成コードで使用される C 型をインポートする。
1220    /// `size_t` などは Rust 組み込み型のエイリアスとして定義。
1221    pub fn default_use_statements() -> Vec<String> {
1222        vec![
1223            // 生成コードで実際に参照されない type alias / import が出ても
1224            // CI の `-D warnings` で落ちないよう dead_code / unused_imports を allow。
1225            "#[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    /// use 文を設定
1233    pub fn with_use_statements(mut self, statements: Vec<String>) -> Self {
1234        self.use_statements = statements;
1235        self
1236    }
1237
1238    /// use 文を追加
1239    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/// 生成ステータス
1246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1247pub enum GenerateStatus {
1248    /// 正常生成
1249    Success,
1250    /// パース失敗(S式をコメント出力)
1251    ParseFailed,
1252    /// 型推論不完全(型付S式をコメント出力)
1253    TypeIncomplete,
1254    /// 利用不可関数を呼び出す(コメント出力)
1255    CallsUnavailable,
1256    /// goto を含む(生成対象から除外)
1257    ContainsGoto,
1258    /// ジェネリクス型パラメータを含む(Rust の as T キャスト不可)
1259    GenericUnsupported,
1260    /// スキップ(対象外)
1261    Skip,
1262}
1263
1264/// 文が goto を含むか再帰的に検査
1265fn 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
1283/// ブロック項目リストが goto を含むか検査
1284fn 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
1291/// 文がトップレベルで `break;` を含むか検査
1292/// (ネストされた loop/switch 内の break は除外)。
1293fn 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        // ネストした loop/switch 内の break は「外側ループ」に関係ないので
1306        // 再帰しない
1307        _ => false,
1308    }
1309}
1310
1311/// コード生成統計
1312#[derive(Debug, Clone, Default)]
1313pub struct CodegenStats {
1314    /// 正常生成されたマクロ数
1315    pub macros_success: usize,
1316    /// パース失敗マクロ数
1317    pub macros_parse_failed: usize,
1318    /// 型推論失敗マクロ数
1319    pub macros_type_incomplete: usize,
1320    /// 利用不可関数呼び出しマクロ数
1321    pub macros_calls_unavailable: usize,
1322    /// カスケード依存でコメントアウトされたマクロ数
1323    pub macros_cascade_unavailable: usize,
1324    /// ジェネリクス未対応マクロ数
1325    pub macros_generic_unsupported: usize,
1326    /// 未解決シンボルを含むマクロ数
1327    pub macros_unresolved_names: usize,
1328    /// 正常生成された inline 関数数
1329    pub inline_fns_success: usize,
1330    /// 型推論失敗 inline 関数数
1331    pub inline_fns_type_incomplete: usize,
1332    /// 未解決シンボルを含む inline 関数数
1333    pub inline_fns_unresolved_names: usize,
1334    /// カスケード依存でコメントアウトされた inline 関数数
1335    pub inline_fns_cascade_unavailable: usize,
1336    /// goto を含む inline 関数数
1337    pub inline_fns_contains_goto: usize,
1338}
1339
1340/// codegen の関数別結果。emit された名前と、されなかった名前 → 理由。
1341///
1342/// `CodegenDriver` が出力 (Pass 3) の各マーカー分岐で記録する。
1343/// `--require-codegen-list` の検証 (`check_required`) に使う。
1344/// BTree 系なのは違反レポートの列挙順を決定化するため。
1345#[derive(Debug, Clone, Default)]
1346pub struct CodegenReport {
1347    /// 実関数として emit された名前
1348    pub emitted: BTreeSet<String>,
1349    /// emit されなかった名前 → 理由 (マーカー種別 + 詳細)
1350    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    /// required のうち emit されなかったものを理由付きで返す。
1363    /// 全て emit 済みなら Ok。emitted にも skipped にも無い名前は
1364    /// codegen 対象に現れなかったもの (apidoc 宣言なし、ヘッダに定義なし等)。
1365    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/// `--require-codegen-list` 違反 (必須名が emit されなかった)
1390#[derive(Debug, Clone)]
1391pub struct RequireCodegenError {
1392    pub violations: Vec<RequireViolation>,
1393}
1394
1395/// 1 件の違反: 名前と、emit されなかった理由
1396#[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/// 一つの関数の生成結果
1419#[derive(Debug, Clone)]
1420pub struct GeneratedCode {
1421    /// 生成されたコード
1422    pub code: String,
1423    /// 不完全マーカーの数
1424    pub incomplete_count: usize,
1425    /// 検出された未解決シンボル名(重複なし、出現順)
1426    pub unresolved_names: Vec<String>,
1427    /// 使用された libc 関数名
1428    pub used_libc_fns: HashSet<String>,
1429    /// codegen で検出されたエラー(コメントアウトの理由)
1430    pub codegen_errors: Vec<String>,
1431}
1432
1433impl GeneratedCode {
1434    /// 生成が完全かどうか(不完全マーカーがないか)
1435    pub fn is_complete(&self) -> bool {
1436        self.incomplete_count == 0
1437    }
1438
1439    /// 未解決シンボルがあるかどうか
1440    pub fn has_unresolved_names(&self) -> bool {
1441        !self.unresolved_names.is_empty()
1442    }
1443}
1444
1445/// 単一関数を生成するためのコード生成器(使い捨て)
1446///
1447/// 各関数の生成ごとにフレッシュなインスタンスを作成して使用する。
1448/// 生成中に不完全マーカーが出力された回数をカウントし、
1449/// 生成完了時に `GeneratedCode` として結果を返す。
1450pub struct RustCodegen<'a> {
1451    interner: &'a StringInterner,
1452    /// Enum バリアント辞書(パターンマッチ用)
1453    enum_dict: &'a EnumDict,
1454    /// マクロ推論コンテキスト(THX マクロ呼び出し判定用)
1455    macro_ctx: &'a MacroInferContext,
1456    /// bindings.rs から抽出した情報
1457    bindings_info: BindingsInfo,
1458    /// 内部バッファ(生成結果を蓄積)
1459    buffer: String,
1460    /// 不完全マーカーの生成回数
1461    incomplete_count: usize,
1462    /// 現在生成中のマクロの型パラメータマップ
1463    /// 仮引数名(InternedStr) → ジェネリック名("T", "U", ...)
1464    current_type_param_map: HashMap<InternedStr, String>,
1465    /// 現在生成中のマクロのリテラル文字列パラメータ名の集合
1466    current_literal_string_params: HashSet<InternedStr>,
1467    /// 現在生成中の関数の戻り値型
1468    current_return_type: Option<UnifiedType>,
1469    /// Call式のlvalue展開時に使用するパラメータ置換テーブル
1470    /// マクロ仮引数名 → 実引数のRust文字列
1471    param_substitutions: HashMap<InternedStr, String>,
1472    /// 現在生成中の関数のパラメータ型情報
1473    /// パラメータ名 → 型
1474    current_param_types: HashMap<InternedStr, UnifiedType>,
1475    /// 既知シンボル集合への参照(未解決シンボル検出用)
1476    known_symbols: &'a KnownSymbols,
1477    /// 現在の関数のローカルスコープ(パラメータ名 + ローカル変数名)
1478    current_local_names: HashSet<InternedStr>,
1479    /// 検出された未解決シンボル名(重複なし、出現順)
1480    unresolved_names: Vec<String>,
1481    /// 使用された libc 関数名
1482    used_libc_fns: HashSet<String>,
1483    /// Rust 宣言辞書への参照(関数パラメータ型参照用)
1484    rust_decl_dict: Option<&'a RustDeclDict>,
1485    /// inline 関数辞書への参照(戻り値型/引数型判定用)
1486    inline_fn_dict: Option<&'a crate::inline_fn::InlineFnDict>,
1487    /// FieldsDict への参照(共通フィールドマクロの canonical type 参照用)
1488    fields_dict: Option<&'a crate::fields_dict::FieldsDict>,
1489    /// 構造体フィールド名 → 型の逆引きマップ
1490    field_type_map: HashMap<String, UnifiedType>,
1491    /// AST ダンプ対象関数名(デバッグ用)
1492    dump_ast_for: Option<String>,
1493    /// 型推論ダンプ対象関数名(デバッグ用)
1494    dump_types_for: Option<String>,
1495    /// const ポインタに変換可能なパラメータの引数位置集合
1496    const_pointer_positions: HashSet<usize>,
1497    /// 再代入されるローカル変数名の集合(let mut 判定用)
1498    mut_local_names: HashSet<InternedStr>,
1499    /// Phase 2 の名前使用解析 (local_usage)。zeroed 初期化判定などで参照
1500    current_local_usage: Option<crate::local_usage::LocalUsageAnalysis>,
1501    /// 本体で未使用のパラメータ名(`_` prefix を付ける。GH #22)
1502    unused_param_names: HashSet<InternedStr>,
1503    /// codegen で検出されたエラー
1504    codegen_errors: Vec<String>,
1505    /// このマクロが bool を返すと判定されたか
1506    is_bool_return: bool,
1507    /// codegen で bool を返すと判定されたマクロの集合(呼び出し先の bool 判定用)
1508    bool_return_macros: HashSet<InternedStr>,
1509    /// 対象 perl が threaded build か(false なら my_perl 注入を抑止)
1510    perl_threaded: bool,
1511}
1512
1513/// コード生成全体を管理する構造体
1514///
1515/// 実際の出力先(Write)を保持し、生成の成功/失敗に応じて
1516/// 適切な形式で出力する。
1517pub struct CodegenDriver<'a, W: Write> {
1518    writer: W,
1519    interner: &'a StringInterner,
1520    /// Enum バリアント辞書(パターンマッチ用)
1521    enum_dict: &'a EnumDict,
1522    /// マクロ推論コンテキスト(THX マクロ呼び出し判定用)
1523    macro_ctx: &'a MacroInferContext,
1524    /// bindings.rs から抽出した情報
1525    bindings_info: BindingsInfo,
1526    config: CodegenConfig,
1527    stats: CodegenStats,
1528    /// 関数別の生成結果 (--require-codegen-list 検証用)
1529    report: CodegenReport,
1530    /// 生成されたコード全体で使用された libc 関数名
1531    used_libc_fns: HashSet<String>,
1532    /// 正常生成された inline 関数名(クロスドメインカスケード検出用)
1533    successfully_generated_inlines: HashSet<InternedStr>,
1534    /// 生成可能と予測されるマクロの集合(inline→macro カスケード検出用)
1535    generatable_macros: HashSet<InternedStr>,
1536    /// const ポインタに変換可能なマクロパラメータ: マクロ名 → const パラメータの引数位置集合
1537    const_pointer_params: HashMap<InternedStr, HashSet<usize>>,
1538    /// bool を返すと判定されたマクロの集合
1539    bool_return_macros: HashSet<InternedStr>,
1540    /// 対象 perl が threaded build か(false なら my_perl 注入を抑止)
1541    perl_threaded: bool,
1542}
1543
1544impl<'a> RustCodegen<'a> {
1545    /// 新しい単一関数用コード生成器を作成
1546    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            // デフォルトは threaded(後方互換)。Driver 経由で
1585            // with_perl_threaded() で上書きされる。
1586            perl_threaded: true,
1587        }
1588    }
1589
1590    /// 対象 perl が threaded かを設定
1591    pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
1592        self.perl_threaded = threaded;
1593        self
1594    }
1595
1596    /// AST ダンプ対象関数名を設定(デバッグ用)
1597    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    /// FieldsDict への参照を設定
1608    pub fn with_fields_dict(mut self, dict: &'a crate::fields_dict::FieldsDict) -> Self {
1609        self.fields_dict = Some(dict);
1610        // bindings.rs に無い自動生成 struct (body_details 等) の
1611        // フィールド型を field_type_map にマージし、Member 式の型推論で
1612        // 利用できるようにする。bindings.rs 側で既に登録されている
1613        // フィールドは優先する。
1614        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    /// const ポインタ位置を設定
1629    pub fn with_const_pointer_positions(mut self, positions: HashSet<usize>) -> Self {
1630        self.const_pointer_positions = positions;
1631        self
1632    }
1633
1634    /// bool 戻り値フラグと bool マクロ集合を設定
1635    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    /// 指定された関数名が AST ダンプ対象かどうかを判定し、対象なら AST をコメントとして出力
1642    /// 型推論結果を stderr にダンプ(デバッグ用)
1643    fn dump_type_info(&self, name_str: &str, info: &MacroInferInfo, params_str: &str, return_type: &str) {
1644        eprintln!("=== Type dump for {} ===", name_str);
1645        // パラメータ型
1646        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            // 全制約を表示
1650            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        // 戻り値型
1676        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        // return_constraints (apidoc 由来)
1682        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        // ルート式の全制約
1689        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    /// 指定された関数名が AST ダンプ対象かどうかを判定し、対象なら CompoundStmt をコメントとして出力
1738    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    /// Call 式が lvalue マクロ呼び出しなら、展開済み lvalue を syn::Expr で返す。
1758    /// パラメータ置換マップは依然 `String` だが、本体の AST 走査は
1759    /// `build_syn_expr` を経由するため `expr_to_rust*` への依存はない。
1760    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) = &macro_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    /// ポインタ式をbool条件に変換するラッパー(inline関数用)— 統一版に委譲
1787    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    /// 式の型を推定(inline 関数用)— 統一版に委譲
1792    fn infer_expr_type_inline(&self, expr: &Expr) -> Option<UnifiedType> {
1793        self.infer_expr_type_unified(expr, None)
1794    }
1795
1796    /// TypeName から型文字列を取得(読み取り専用、整数型を正しく解決する版)
1797    fn type_name_to_type_str_readonly(&self, type_name: &crate::ast::TypeName) -> String {
1798        // ポインタの個数をカウント
1799        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        // const チェック:
1803        // C の "const T *p" → pointee は const → Rust: *const T
1804        //   この場合 const は specs.qualifiers.is_const にある
1805        // C の "T * const p" → ポインタ自体が const (再代入不可) → Rust: *mut T
1806        //   こ���場合 const は Pointer(qualifiers.is_const) にある → Rust の *const ではない
1807        let is_const_ptr = pointer_count == 1 && type_name.specs.qualifiers.is_const;
1808        // 基本型を取得
1809        let base = self.base_type_str_readonly(&type_name.specs.type_specs);
1810        // ポインタをラップ
1811        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    /// TypeSpec リストから基本型名を取得する(読み取り専用)
1820    fn base_type_str_readonly(&self, type_specs: &[TypeSpec]) -> String {
1821        // typedef 名を優先
1822        for spec in type_specs {
1823            if let TypeSpec::TypedefName(name) = spec {
1824                return self.interner.get(*name).to_string();
1825            }
1826        }
1827        // struct/union/enum 名
1828        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    /// 式の型を推定(macro 関数用)— 統一版に委譲
1872    fn infer_expr_type(&self, expr: &Expr, info: &MacroInferInfo) -> Option<UnifiedType> {
1873        self.infer_expr_type_unified(expr, Some(info))
1874    }
1875
1876    // ================================================================
1877    // 統一型推論 (macro/inline 共通)
1878    // ================================================================
1879
1880    /// 式の型を推定(macro/inline 統一版)
1881    ///
1882    /// `info` が Some の場合は TypeEnv (Tier ベース) も参照する(マクロ用)。
1883    /// None の場合は current_param_types のみ参照する(inline 用)。
1884    fn infer_expr_type_unified(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> Option<UnifiedType> {
1885        match &expr.kind {
1886            ExprKind::Ident(name) => {
1887                // current_param_types を最優先(Tier ベースで決定済み)
1888                if let Some(ut) = self.current_param_types.get(name) {
1889                    return Some(ut.clone());
1890                }
1891                // TypeEnv 参照(マクロ用: Tier ベースで最良の制約を選択)
1892                if let Some(info) = info {
1893                    // param_to_exprs 経由の expr_constraints
1894                    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                    // param_constraints(フォールバック、Tier ベース)
1912                    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                // 定数の型
1927                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                    // extern static 変数の型 (PL_utf8skip など)
1933                    if let Some(ty_str) = dict.static_types.get(name_str) {
1934                        return Some(UnifiedType::from_rust_str(ty_str));
1935                    }
1936                }
1937                // enum バリアント(C 側 EnumDict 由来)。bindings.rs では nominal
1938                // 型の variant として現れるため、属する enum 名を Named 型として
1939                // 返す。比較・ビット演算等での enum→int キャスト挿入で利用。
1940                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                // まず base 式の型から struct を特定し、fields_dict で
1951                // メンバ型を正確に引く (同名フィールドが別 struct に存在する
1952                // 場合の誤解決を避ける)。見つからなければ field_type_map に
1953                // フォールバック。
1954                let resolve_struct_name = |this: &Self| -> Option<String> {
1955                    // マクロ推論の type_env を優先
1956                    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                    // inline 関数のローカル / パラメータ: UnifiedType 経由で
1971                    // 推論して Named を取り出す
1972                    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                // fields_dict の C ソース由来型を第一優先 (同名フィールドが
1986                // 別 struct に存在するケースの誤解決を避けるため struct 名で
1987                // 限定)。ただし C 側で `[T; SVt_LAST]` のようにサイズが定数式で
1988                // 未解決の場合は `*mut T` になり配列情報を失うので、
1989                // field_type_map (bindings.rs 由来の Array) の方を優先する
1990                // フォールバックを組み合わせる。
1991                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                // field_type_map が配列で fields_dict がポインタなら ftm を採用。
2003                // (SVt_LAST のような unresolved サイズで fields_dict が配列情報を失うケース)
2004                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                // C の `a[i]` は `*(a + i)` と等価。base が配列 / ポインタ
2020                // 型なら要素型を返す。
2021                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 (&lt, &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                        // C のポインタ減算(同型ポインタ同士)は ptrdiff_t/isize を返す。
2049                        // `offset_from` メソッド呼び出しに変換されるので isize 扱い。
2050                        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            // Rust の std::mem::size_of / size_of_val は `usize` を返す。
2069            // 旧実装は Int{false, Long} を返していたが、これは to_rust_string
2070            // で "c_ulong" になり usize と混同できず `u64 * usize` 等の
2071            // E0277 を起こした。明示的に Named("usize") にして区別する。
2072            ExprKind::Sizeof(_) | ExprKind::SizeofType(_) => Some(UnifiedType::Named("usize".to_string())),
2073            ExprKind::Call { func, .. } => {
2074                // メソッド呼び出し: offset/wrapping_add 等はレシーバと同じ型
2075                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                    // 自家生成マクロの戻り値型
2087                    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                    // inline 関数の戻り値型 (自家生成 Perl_utf8_hop 等)
2093                    if let Some(dict) = self.inline_fn_dict {
2094                        if let Some(func_def) = dict.get(*name) {
2095                            // 戻り値型を文字列組立 (読取専用 API を使用)
2096                            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    /// 式がポインタ型かどうかを推定(macro/inline 統一版)
2143    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    /// 式の型が `Option<fn(...)>` / `Option<unsafe extern "C" fn(...)>`
2225    /// または同型の typedef エイリアスかを判定する。
2226    ///
2227    /// bindgen 由来の関数ポインタフィールドは `Option<fn(...)>` で包まれる。
2228    /// この形式は整数 0 との `==`/`!=` 比較で `expected Option<...>` エラーを
2229    /// 起こすため、呼出側で `.is_some()`/`.is_none()` に変換する。
2230    fn is_option_fn_pointer_expr(&self, expr: &Expr, info: Option<&MacroInferInfo>) -> bool {
2231        // Member/PtrMember の直接フォールバック: infer が None を返す
2232        // (inline 関数のローカル変数など)場合に備えて、field_type_map で
2233        // フィールド名から直接 fn pointer 型か確認する。
2234        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        // typedef エイリアス経由: dict.types で展開して fn 形式か確認
2256        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    /// ポインタ式をbool条件に変換するラッパー(macro/inline 統一版)
2267    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        // パラメータが bool 型なら != 0 不要
2272        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        // フィールドが bool 型なら != 0 不要
2280        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        // __builtin_expect(cond, val) → cond の型をチェック
2289        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        // Option<fn(...)> は `!= 0` で比較できず、真偽判定は .is_some()。
2300        // field_type_map 経由でフィールド名から検出する。
2301        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            // `!{expr}.is_null()` 直付けだと expr が Cast の場合に
2307            // `x as T.is_null()` となり E0001 系 (cast cannot be followed
2308            // by method call)。必ず paren で包んで method chain の対象を
2309            // 明確化する。
2310            return format!("!({}).is_null()", expr_str);
2311        }
2312        format!("({} != 0)", strip_outer_parens(expr_str))
2313    }
2314
2315    /// 呼び出し先が THX マクロで、my_perl が不足しているかチェック
2316    ///
2317    /// 以下の条件を満たす場合に true を返す:
2318    /// 1. 呼び出し先が MacroInferContext.macros に存在する
2319    /// 2. その MacroInferInfo.is_thx_dependent が true
2320    /// 3. 実引数が仮引数より1つ少ない(my_perl が不足)
2321    fn needs_my_perl_for_call(&self, func_name: crate::InternedStr, actual_arg_count: usize) -> bool {
2322        // 非 threaded perl では my_perl 引数自体が存在しないので必ず false。
2323        // is_thx_dependent は既に Phase 2 で false になっているはずだが、
2324        // 防御的にここでも mode をチェック。
2325        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                // THX マクロの期待引数数 = params.len() + 1 (my_perl)
2331                let expected_count = callee_info.params.len() + 1;
2332                // 実引数が1つ少ない場合、my_perl が必要
2333                return actual_arg_count + 1 == expected_count;
2334            }
2335        }
2336        false
2337    }
2338
2339    /// 式が既知の static 配列名かどうかをチェック
2340    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    /// 式が「ポインタに減衰させて `.as_ptr()` を付けるべき配列値」か判定。
2350    /// Ident (static 配列)、struct フィールドの配列型、どちらも対象。
2351    ///
2352    /// ただし flexible-array フィールド(`char data[]` 等)は
2353    /// `maybe_decay_flex_array` が `&raw const field as *mut T` に既に
2354    /// 変換済みであるため、ここでは配列扱いしない。そうしないと
2355    /// `ptr.as_ptr()` の二重適用が発生する。
2356    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        // flex array のメンバアクセスは除外(既に pointer にデケイ済)
2361        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    /// フィールド名がビットフィールドメソッドかどうかをチェック
2390    ///
2391    /// 構造体名が不明な場合は、全構造体のビットフィールドメソッド名を検索
2392    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    /// 呼び出し先マクロのジェネリック型パラメータ情報を取得
2398    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    /// キャスト先の型が enum 型かどうか判定
2411    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    /// 呼び出し先マクロの特定の引数位置がリテラル文字列パラメータかチェック
2423    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    /// 呼び出し先関数の指定引数位置の型を取得
2431    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    /// 呼び出し先関数のパラメータ型を取得(inline 関数/マクロ関数もフォールバック)
2438    fn get_callee_param_type_extended(&mut self, func_name: &str, arg_index: usize) -> Option<UnifiedType> {
2439        // 0. 既知 libc 関数のハードコード型 (bindings.rs に無く、
2440        //    呼出側が `*mut c_char` を渡すが実際は `*mut c_void` が期待される
2441        //    ケースで as-cast を自動挿入するため)。
2442        if let Some(ut) = libc_fn_param_type(func_name, arg_index) {
2443            return Some(ut);
2444        }
2445        // 1. bindings.rs
2446        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            // 2. inline 関数
2451            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            // 3. 自家生成マクロ関数の type_env からパラメータ型を取得
2465            if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2466                // THX 依存の場合、arg_index 0 は my_perl なのでスキップ。
2467                // 非 threaded では my_perl が存在しないので素通り。
2468                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                    // best-tier 制約 (param.expr_id() + param_to_exprs 全 ExprId 走査)
2478                    // 宣言型 (`get_param_type`) と同じ選択方式に揃え、
2479                    // 呼出側のキャスト判定が真の宣言と一致するようにする。
2480                    if let Some(mut ty) = best_constraint_for_macro_param(macro_info, param) {
2481                        // const/mut も callee 側の最終宣言と一致させる
2482                        // (get_param_type と同じロジック: const_pointer_positions に含まれていれば const)
2483                        let should_be_const = macro_info
2484                            .const_pointer_positions
2485                            .contains(&macro_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    /// 呼び出し先関数の指定引数位置が bool 型かどうか判定(自家生成マクロも参照)
2501    fn callee_param_is_bool(&self, func_name: &str, arg_index: usize) -> bool {
2502        // 1. bindings.rs の関数
2503        if let Some(param_ut) = self.get_callee_param_type(func_name, arg_index) {
2504            return param_ut.is_bool();
2505        }
2506        // 2. 自家生成マクロ関数のパラメータ型
2507        if let Some(interned) = self.interner.lookup(func_name) {
2508            if let Some(macro_info) = self.macro_ctx.macros.get(&interned) {
2509                // THX マクロは my_perl が自動挿入されるのでオフセットを引く。
2510                // 非 threaded では my_perl 注入が無いのでオフセット 0。
2511                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                    // type_env からパラメータの型制約を取得
2521                    if let Some(expr_ids) = macro_info.type_env.param_to_exprs.get(&param.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            // 3. 自家生成 inline 関数のパラメータ型
2536            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    /// 呼び出し先関数の戻り値型を取得
2559    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    /// `UnifiedType` が bindings.rs 上の Rust enum 型を指すかを判定。
2566    /// (C 側では int 互換だが、Rust 側は nominal 型なので、整数演算には
2567    /// `as <int>` キャストが必要になる)
2568    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    /// 式が bool を返すかどうかを判定(関数の戻り値型も考慮)
2578    fn is_bool_expr_with_dict(&self, expr: &Expr) -> bool {
2579        if is_boolean_expr_recursive(expr, self.interner) {
2580            return true;
2581        }
2582        // 配列インデックス: 配列要素型が bool なら bool
2583        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                    // static 配列: 名前が PL_valid_types_* なら bool 配列
2595                    if dict.statics.contains(name_str) && name_str.starts_with("PL_valid_types_") {
2596                        return true;
2597                    }
2598                }
2599            }
2600        }
2601        // パラメータが bool 型
2602        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        // フィールドが bool 型
2610        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        // 関数呼び出しの戻り値型が bool かチェック
2619        if let ExprKind::Call { func, .. } = &expr.kind {
2620            if let ExprKind::Ident(name) = &func.kind {
2621                // 0. codegen で bool と判定されたマクロ
2622                if self.bool_return_macros.contains(name) {
2623                    return true;
2624                }
2625                let func_name = self.interner.get(*name);
2626                // 1. bindings.rs の関数
2627                if let Some(ret_ut) = self.get_callee_return_type(func_name) {
2628                    return ret_ut.is_bool();
2629                }
2630                // 2. 自家生成マクロ関数の戻り値型
2631                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                // 3. 自家生成 inline 関数の戻り値型
2638                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        // MacroCall の場合も bool_return_macros をチェック
2650        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    /// 式の最内部にある literal_string_param の Ident を探す
2659    /// identity builtin(ASSERT_IS_LITERAL 等)を透過して中身をチェック
2660    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                // identity builtin (ASSERT_IS_LITERAL, ASSERT_IS_PTR, ASSERT_NOT_PTR)
2667                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    /// マクロ呼び出し形式で出力すべきかを判定
2684    ///
2685    /// 以下の場合にマクロ呼び出し形式で出力する:
2686    /// - MacroInferContext に登録されており、生成対象である
2687    ///
2688    /// そうでない場合は展開形式で出力する。
2689    fn should_emit_as_macro_call(&self, name: crate::InternedStr) -> bool {
2690        // MacroInferContext にマクロ情報があり、パース可能なら生成対象
2691        if let Some(info) = self.macro_ctx.macros.get(&name) {
2692            // パース成功し、利用不可関数を呼ばないマクロのみ
2693            return info.is_parseable() && !info.calls_unavailable;
2694        }
2695        false
2696    }
2697
2698    /// 不完全マーカー: 型が不明
2699    fn unknown_marker(&mut self) -> &'static str {
2700        self.incomplete_count += 1;
2701        "/* unknown */"
2702    }
2703
2704    /// 不完全マーカー: TODO
2705    fn todo_marker(&mut self, msg: &str) -> String {
2706        self.incomplete_count += 1;
2707        format!("/* TODO: {} */", msg)
2708    }
2709
2710    /// 不完全マーカー: 型
2711    fn type_marker(&mut self) -> &'static str {
2712        self.incomplete_count += 1;
2713        "/* type */"
2714    }
2715
2716    /// Declaration から変数名を収集して current_local_names に追加
2717    /// ローカル変数の型も current_param_types に登録(ポインタ検出用)
2718    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    /// 関数本体全体を再帰的に走査して、ネストした compound 内・StmtExpr 内・
2730    /// for ループ初期化部の Declaration を全て `current_local_names` に追加する。
2731    /// scope 厳密性は犠牲にして「同一名はどのスコープでも解決済み」と扱う簡易版。
2732    /// `STMT_START { let v = ...; ... } STMT_END` 展開で生まれる block-local
2733    /// 変数を未解決と誤検出しないようにする。
2734    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        // 他の式ノードに含まれる StmtExpr は普通存在しない(C 文法上)が、
2794        // 念のため簡易的に再帰しておく
2795        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    /// Declaration からローカル変数の型のみ収集して current_param_types に追加
2830    /// (current_local_names には追加しない — 未解決シンボル検出に影響しないように)
2831    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    /// バッファに行を書き込み
2842    fn writeln(&mut self, s: &str) {
2843        self.buffer.push_str(s);
2844        self.buffer.push('\n');
2845    }
2846
2847    /// 生成結果を取得(self を消費)
2848    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    /// マクロ関数を生成(self を消費)
2859    pub fn generate_macro(mut self, info: &MacroInferInfo) -> GeneratedCode {
2860        let name_str = self.interner.get(info.name);
2861
2862        // ローカルスコープ: マクロのパラメータ名を登録
2863        for p in &info.params {
2864            self.current_local_names.insert(p.name);
2865        }
2866
2867        // 型パラメータマップを構築
2868        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        // 型パラメータになったパラメータは通常パラメータとしては存在しないので
2876        // current_local_names から除外する(ジェネリック誤検出時に unresolved 検出するため)
2877        for (name, _) in &self.current_type_param_map {
2878            self.current_local_names.remove(name);
2879        }
2880
2881        // リテラル文字列パラメータの名前集合を構築
2882        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        // ジェネリック句を生成
2887        let generic_clause = self.build_generic_clause(info);
2888
2889        // パラメータリストを構築(型情報付き)
2890        // type/cast パラメータは値引数ではないので除外
2891        let params_with_types = self.build_param_list(info);
2892
2893        // 戻り値の型を取得(current_return_type にもセット)
2894        let return_type = self.get_return_type(info);
2895        self.current_return_type = Some(UnifiedType::from_rust_str(&return_type));
2896
2897        // 型推論ダンプ
2898        if self.dump_types_for.as_deref() == Some(name_str) {
2899            self.dump_type_info(name_str, info, &params_with_types, &return_type);
2900        }
2901
2902        // THX 依存の場合は my_perl パラメータを追加。
2903        // 非 threaded perl では my_perl 自体が存在しないので注入しない。
2904        let thx_param = if self.perl_threaded && info.is_thx_dependent {
2905            "my_perl: *mut PerlInterpreter"
2906        } else {
2907            ""
2908        };
2909
2910        // 関数シグネチャ
2911        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        // AST ダンプ(デバッグ用)
2920        self.dump_ast_comment_for_expr(name_str, &info.parse_result);
2921
2922        // ドキュメントコメント
2923        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        // 関数定義(ジェネリック句付き)
2930        self.writeln(&format!("pub unsafe fn {}{}({}) -> {} {{", name_str, generic_clause, params_str, return_type));
2931
2932        // unsafe 操作(関数呼び出し or デリファレンス)を含む場合のみ unsafe ブロックを生成
2933        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                        // `!x.is_null()` 直付けだと x が cast の場合に
2955                        // `x as T.is_null()` と解釈される。必ず括弧で包む。
2956                        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; // 空文 (空マクロ消去跡)
2974                        }
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    /// ジェネリック句を生成(例: "<T>" or "<T, U>")
2995    fn build_generic_clause(&self, info: &MacroInferInfo) -> String {
2996        if info.generic_type_params.is_empty() {
2997            return String::new();
2998        }
2999
3000        // 型パラメータを収集(重複排除、ソート)
3001        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    /// パラメータリストを構築(型情報付き)
3009    /// type/cast パラメータは型パラメータなので値引数からは除外する
3010    /// 副作用: 各パラメータの型を current_param_types に登録し、
3011    /// Phase 2 の名前使用解析を self (mut_local_names / unused_param_names /
3012    /// current_local_usage) に反映する
3013    fn build_param_list(&mut self, info: &MacroInferInfo) -> String {
3014        // Phase 2 (analyze_all_macros) で計算済みの解析を読む。
3015        // テスト等で未設定の場合のみその場で計算する
3016        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            // 未使用パラメータは `_` prefix (unused_variables 対策、GH #22)。
3032            // 本体に参照が無いことが保証されるので束縛名だけ変えれば良い
3033            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            // current_param_types に登録(bool 判定等で使用)
3040            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    /// パラメータの型を取得
3048    fn get_param_type(&mut self, param: &MacroParam, info: &MacroInferInfo, param_index: usize) -> String {
3049        // ジェネリック型パラメータかチェック
3050        if let Some(generic_name) = info.generic_type_params.get(&(param_index as i32)) {
3051            return generic_name.clone();
3052        }
3053
3054        // リテラル文字列パラメータかチェック(apidoc の "..." 引数)
3055        if info.literal_string_params.contains(&param_index) {
3056            return "&str".to_string();
3057        }
3058
3059        let should_be_const = self.const_pointer_positions.contains(&param_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                // must-mut: Phase 2 で *mut と確定 → *const になっていたら *mut に戻す
3066                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    /// 戻り値の型を取得
3075    ///
3076    /// ジェネリック戻り値型を優先し、なければ
3077    /// MacroInferInfo::get_return_type() を使用して、
3078    /// return_constraints(apidoc由来)を expr_constraints より優先する
3079    fn get_return_type(&mut self, info: &MacroInferInfo) -> String {
3080        // ジェネリック戻り値型かチェック(-1 = return type)
3081        if let Some(generic_name) = info.generic_type_params.get(&-1) {
3082            return generic_name.clone();
3083        }
3084
3085        // 依存順パスで bool と判定されていればそのまま bool を返す
3086        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                        // 式の推論型がポインタで const なら戻り値も const に
3096                        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                    // "()" が返された場合: 式の実際の型を確認
3106                    // 式が本当に void を返す(void 関数呼び出し等)なら "()" で正しい
3107                    // そうでなければ型推論の誤りなのでフォールバック
3108                    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                    // 式型推論でも "()" → void で正しい
3115                    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    /// TypeRepr を Rust 型文字列に変換
3125    ///
3126    /// 戻り値に `/*` が含まれていたら不完全型としてカウントする
3127    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    /// 型文字列中の型パラメータ名を generic 名に置換
3137    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            // 単語境界を考慮した置換(部分文字列一致を避ける)
3145            result = replace_word(&result, name_str, generic_name);
3146        }
3147        result
3148    }
3149
3150    /// MUTABLE_PTR パターンを検出
3151    ///
3152    /// `({ void *p_ = (expr); p_; })` のような構造を検出し、
3153    /// 初期化子の式を返す。
3154    fn detect_mutable_ptr_pattern<'b>(&self, compound: &'b CompoundStmt) -> Option<&'b Expr> {
3155        // 2つの要素: 宣言 + 式文
3156        if compound.items.len() != 2 {
3157            return None;
3158        }
3159
3160        // 最初の要素: 宣言
3161        let decl = match &compound.items[0] {
3162            BlockItem::Decl(d) => d,
3163            _ => return None,
3164        };
3165
3166        // 宣言子が1つで、初期化子がある
3167        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        // 初期化子は式
3175        let init_expr = match init {
3176            Initializer::Expr(e) => e.as_ref(),
3177            _ => return None,
3178        };
3179
3180        // 2番目の要素: 式文で、宣言した変数を参照
3181        let last_expr = match &compound.items[1] {
3182            BlockItem::Stmt(Stmt::Expr(Some(e), _)) => e,
3183            _ => return None,
3184        };
3185
3186        // 最後の式が宣言した変数への参照
3187        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    // ================================================================
3197    // syn::Expr ベースの式構築 (Step 1+)
3198    // ================================================================
3199
3200    /// flexible array member の field access を `&raw const place as *mut T`
3201    /// に変換する。配列名→ポインタ decay の C 慣用句を Rust で正しく表現する。
3202    ///
3203    /// 検出条件: base 式の TypeRepr から typedef/struct 名を取り、
3204    /// `FieldsDict::flexible_array_element` が要素型を返した場合のみ変換。
3205    /// それ以外は `access` をそのまま返す。
3206    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        // `&raw const access as *mut <element>` を生成
3232        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    /// `&MACRO(args)` の AddrOf inner が「自家生成マクロへの Call」で、
3245    /// 呼び出し先が **Expression body**(lvalue chain として展開可能)なら、
3246    /// 本体式を引数で alpha 置換した `Expr` を返す。
3247    ///
3248    /// 用途: `&GvSV(gv)` のような C 慣用句で、Rust 側の wrap 関数が
3249    /// temporary を返すため `&raw mut <fn_call>` が E0745 になる問題の回避。
3250    /// マクロ本体を inline 展開して `&raw mut (*GvGP(gv)).gp_sv` のような
3251    /// 真の place 式に変換する。
3252    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        // THX 依存だと第一引数が my_perl で arg と zip がずれる → 当面非対応
3268        if callee_info.is_thx_dependent {
3269            return None;
3270        }
3271        if callee_info.params.len() != args.len() {
3272            return None;
3273        }
3274
3275        // param_name → arg_expr の置換マップを構築
3276        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    /// C AST の式を syn::Expr に変換する(macro/inline 統一)
3287    ///
3288    /// `info` が Some の場合はマクロ用、None の場合は inline 用。
3289    /// 未対応の ExprKind は expr_to_rust_ctx のフォールバック文字列を syn::parse_str で変換する。
3290    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                // lvalue展開時のパラメータ置換
3296                if let Some(subst) = self.param_substitutions.get(name) {
3297                    // 置換文字列をパース
3298                    return syn::parse_str(subst).unwrap_or_else(|_| int_lit(0));
3299                }
3300                let name_str = self.interner.get(*name);
3301                // libc 関数の使用を記録
3302                if LIBC_FUNCTIONS.contains(&name_str) {
3303                    self.used_libc_fns.insert(name_str.to_string());
3304                }
3305                // 未解決シンボルチェック
3306                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                // true/false は Rust の bool リテラルとして出力(r#true 回避)
3316                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                // extern static 配列はポインタとして使われるため raw pointer に減衰させる。
3327                //
3328                // Rust 2024 edition では `static mut` への暗黙の shared reference が
3329                // hard error 化された (`creating a shared reference to mutable static`)。
3330                // `.as_ptr()` は内部で `&self -> *const T` の参照経由を行うため、
3331                // `static mut PL_fold_locale: [u8; N]` のような mutable static に対して
3332                // 直接呼ぶと当該 lint を踏む。
3333                //
3334                // - `(&raw const NAME[0])` は const 評価で `[N=0]` の OOB を踏む
3335                //   (bindgen が不明サイズの extern static を `[T; 0]` で出すため)。
3336                // - `(&raw const NAME) as *const u8` は型情報を捨てるため `.offset(i)`
3337                //   が byte 単位になり、要素配列で計算が壊れる。
3338                // - 正解は **`(&raw const NAME) as *const T`**。bindings から要素型 T
3339                //   を取り出して埋め込む。取り出せなかったら u8 にフォールバック。
3340                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                // C の `&MACRO(args)` パターン: マクロが lvalue を返すことを
3382                // 期待する C コード。Rust では MACRO が unsafe fn として
3383                // wrap されるため戻り値が temporary になり `&raw mut <call>`
3384                // が E0745 を起こす。callee の本体式を inline 展開して
3385                // lvalue 性を回復する。
3386                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                    // bitfield → メソッド呼び出し
3409                    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, /*is_ptr_member=*/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, /*is_ptr_member=*/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                // C カンマ `(A, B)` の翻訳。LHS の値は捨てるが、A が
3446                // assignment-as-expression の場合 codegen は `{ stmt; trailing }`
3447                // のような trailing 値付きブロックを作る(例: `*fp |= X` →
3448                // `{ *fp |= X; *fp }`)。これを文の位置で `;` 付きに置くと
3449                // Rust の trailing 単項式・論理演算・must_use 戻り値が discarded で
3450                // CI の `-D warnings` を踏む。
3451                //
3452                // 条件付き `let _ = A;` wrap: A が値を返すと判明している
3453                // パターン(trailing-expr 付き block / 論理演算 / 単項 / 関数呼出)
3454                // のみ wrap する。`{ assert!(...); }` のように常に `()` を返す
3455                // 形式まで wrap すると、既存の生成コードを不必要に汚すため除外。
3456                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                // unsigned 型のキャスト結果に対する負号は wrapping_neg を使用
3478                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                // C の `!"literal"` は 0 (false)。文字列リテラルは常に非 NULL。
3497                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                    // C の `!ptr` は「ptr が NULL か」そのもの。`.is_null()` が
3506                    // 否定を内包するので、外側に ! を重ねてはならない
3507                    // (かつて二重否定になっており、SvPVXtrue 等の null ガードが
3508                    // 反転していた)。
3509                    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                    // 整数 → != 0 して bool に変換、否定は外側 ! が担当
3523                    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                // C の慣用表現 `(unsigned)-1` は最大値を意味する。
3534                // `-1 as T` では E0600 (usize に対する単項 - は不可) になるため、
3535                // `T::MAX` に置換する。`-N` 一般は今は扱わず、`-1` のみ対応。
3536                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                // C の const-cast パターン `(T*)&place`:
3547                // place が `*const` ポインタ deref 経由(例: `(c)->field` で
3548                // `c: *const PERL_CONTEXT`)だと `&raw mut place` が E0596
3549                // になるため、`&raw const place as *mut T` で const を剥がす。
3550                // place が元から mut でも結果は等価(raw pointer の as cast は
3551                // mut/const を問わない)。
3552                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                        // AddrOf の inner が「callee マクロ呼び出し」なら inline 展開
3557                        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                    // void キャスト → 式の値を `let _` で捨てる。
3579                    // 単純な `{ expr; }` だと `must_use` 関数の戻り値(size_of_val 等)、
3580                    // 論理演算 (`a || b`)、単項式 (`*ptr`) を捨てたときに
3581                    // unused_must_use / unused_logical_op / unused_unary lint で
3582                    // CI の `-D warnings` が落ちる。`let _ = expr;` ならどんな式でも
3583                    // 「使った」扱いになり、副作用ある式(assignment, fn call)でも安全。
3584                    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                    // bool キャスト
3590                    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                        // ポインタ → !ptr.is_null()
3596                        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                    // enum キャスト → transmute
3615                    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                // sizeof(literal_string_param) → param.len() + 1
3623                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                // `&` 単項はフィールド/関数呼出より低優先なため、
3633                // `&len + 1` は `(&len) + 1` と解釈される。
3634                // 常に `&(expr)` と paren で包み、normalize_parens で
3635                // 不要な括弧を除去する。
3636                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                    // 配列ベースを raw pointer に減衰させる。
3650                    // - 通常: `array.as_ptr()`
3651                    // - extern static (mutable static 含む): `((&raw const NAME) as *const T)`
3652                    //   (Rust 2024 で `static mut` への shared reference が hard error 化。
3653                    //   `.as_ptr()` 経由の暗黙参照を避ける。要素型 T は bindings から取得)
3654                    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                    // 要素型を可能な限り抽出して `*mut ELEM` にキャスト。
3675                    // `as_ptr()` / `&raw const` どちらも `*const T` だが、後段で
3676                    // `&mut a[i]` を取るときに E0596 を避けるため mut へ寄せる。
3677                    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                // Fix 3: type_hint ベースの null→null_ptr, 0/1→bool 変換
3702                if let Some(ref hint) = type_hint {
3703                    let hint_ut = UnifiedType::from_rust_str(hint);
3704                    if hint_ut.is_pointer() {
3705                        // type_hint (current_return_type) はマクロ全体の戻り値で、
3706                        // call 引数内の入れ子三項にも渡ってくる。反対 arm の実推論型が
3707                        // 非ポインタ (整数フラグ等) なら、この 0 はフラグの 0 であって
3708                        // NULL ではない (例: 5.44 hv_fetch の
3709                        // `HV_FETCH_JUST_SV | (lval ? HV_FETCH_LVALUE : 0)`)。
3710                        // その場合は null 化せず arm ベースのフォールバックに任せる
3711                        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                    // 整数型の type_hint + 片方が null リテラル → null を 0 に。
3729                    // C `cond ? i : 0` の 0 がマクロ展開で NULL になっているケース。
3730                    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                // null リテラル分岐の型推論(type_hint がない場合のフォールバック)
3756                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                // Fix 2: wider_integer_type キャスト
3773                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                    // SV サブタイプ間: 両枝を共通型 (type_hint 優先、なければ then 型)
3789                    // に揃えて if/else 型整合を確保する。
3790                    if tut.is_pointer() && eut.is_pointer() && ts != es
3791                        && is_sv_subtype_cast(tut, eut)
3792                    {
3793                        // type_hint が void (`()` や `c_void`) の場合は cast 対象に
3794                        // しない (return 型が void の文脈で分岐値は捨てられる)。
3795                        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                // sizeof(literal_string_param) - 1 → param.len()
3811                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                // C 文字列リテラル vs 0 比較 → 常に非 NULL (c"..." は &CStr)
3826                //   `c"..." == 0` → false / `c"..." != 0` → true
3827                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                // Option<fn(...)> == 0 / != 0 → .is_none() / .is_some()
3840                // bindgen の関数ポインタフィールドは Option で包まれるため、
3841                // ポインタ null 比較より先に Option 判定を行う。
3842                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                // ポインタ == 0 / != 0 → .is_null()
3859                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                    // bool_expr != 0 → bool_expr, bool_expr == 0 → !bool_expr
3895                    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                // ポインタ ± 整数 → .offset()
3928                if matches!(op, BinOp::Add | BinOp::Sub) {
3929                    // static 配列の Ident (`bodies_by_type` 等) は build_syn_expr
3930                    // が既に `.as_ptr()` を付加するため、`l_arr` には含めない。
3931                    // ここで再度 `.as_ptr()` を被せると *const T に対して呼ばれて
3932                    // E0599 になる。非 Ident の「フィールド直値が配列型」に限定。
3933                    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                    // 配列値に対して `(arr.as_ptr() as *mut ELEM)` で mut pointer を
3946                    // 作るヘルパ。l_arr は field-access の配列(build_syn_expr が
3947                    // `.as_ptr()` を付けない)、is_static_array は Ident の static
3948                    // 配列(build_syn_expr が既に `.as_ptr()` を付ける)。どちらの
3949                    // ケースでも結果が `*const T` にならないよう `*mut T` へ cast
3950                    // する。
3951                    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, /*needs_as_ptr=*/true)
3973                        } else if l_is_static_arr {
3974                            cast_to_mut(self, l, lhs, /*needs_as_ptr=*/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, /*needs_as_ptr=*/true)
3994                        } else if r_is_static_arr {
3995                            cast_to_mut(self, r, rhs, /*needs_as_ptr=*/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                // float vs int literal → float に変換
4010                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                // ポインタ比較で const/mut が違う場合の cast。
4036                // `*mut T < *const T` は Rust で E0308(types differ in mutability)。
4037                // rhs を lhs の型に合わせる(wrapper の呼出規約で lhs が mut、
4038                // callee 由来の rhs が const になりやすい)。
4039                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                // 論理演算子: bool 変換
4065                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                // 型キャスト挿入(整数幅、bool→int、float↔int、enum→int)
4080                let lt = self.infer_expr_type_unified(lhs, info);
4081                let rt = self.infer_expr_type_unified(rhs, info);
4082
4083                // 片側だけ判定可能でも enum は必ず integer にキャストする。
4084                // `cs << 7` のように rhs が IntLit Binary で型推論 None の
4085                // ケースを拾う(enum 単独で Shl/BitOr 等が定義されていない)。
4086                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 (&lt, &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)) = (&lt, &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                    // enum → integer キャスト(C 側は int 互換だが Rust enum は
4112                    // nominal 型なので比較・ビット演算で `as <int>` が必要)
4113                    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                    // bool → integer キャスト
4126                    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                    // float ↔ integer キャスト
4139                    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                    // 整数幅不一致 → wider type にキャスト
4150                    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                // float (片方のみ型判明)
4161                {
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 (&lt, &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                    // ビット演算で片方のみ型判明
4183                    if matches!(op, BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor) {
4184                        match (&lt, &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                // 基本の二項演算
4202                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                // 共通フィールドマクロが定義する関数ポインタフィールドの呼び出しを検出。
4211                // `(*x).xcv_root_u.xcv_xsub(args)` のような Member/PtrMember 経由の Call で、
4212                // canonical type が fn ポインタなら `<field>.unwrap_unchecked()(args)` 形式で出力。
4213                if let Some(syn_call) = self.try_build_common_macro_fn_call(func, args, info) {
4214                    return syn_call;
4215                }
4216                // builtin 関数の特殊処理
4217                if let ExprKind::Ident(name) = &func.kind {
4218                    let func_name = self.interner.get(*name);
4219                    // __builtin_expect → 引数を透過
4220                    if func_name == "__builtin_expect" && !args.is_empty() {
4221                        return self.build_syn_expr(&args[0], info);
4222                    }
4223                    // __builtin_unreachable → unreachable_unchecked
4224                    if func_name == "__builtin_unreachable" {
4225                        return syn::parse_str("std::hint::unreachable_unchecked()").unwrap();
4226                    }
4227                    // __builtin_ctz/clz → trailing_zeros/leading_zeros
4228                    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                    // ASSERT_IS_LITERAL 等 → 引数を透過
4245                    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                    // offsetof → std::mem::offset_of!
4251                    //
4252                    // args[0] は本来 BuiltinCall arm で TypeName として処理される。
4253                    // ここに来るのは offsetof が通常の関数呼び出しとしてパースされた
4254                    // ケースで、args[0] は型名を表す Ident になる。build_syn_expr の
4255                    // Ident arm は known_symbols にない名前を unresolved_names に
4256                    // 登録してしまい、cascade 連鎖で依存先まで TYPE_INCOMPLETE 化する。
4257                    // 型名の Ident は名前そのものを使えば十分なので bypass する。
4258                    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                // 関数名を構築
4273                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                // ジェネリック型パラメータのチェック
4282                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                    // turbofish 構文 — 文字列ベースで構築(型引数のため)
4287                    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                // 通常の関数呼び出し — 引数を処理(統一版)
4306                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                // フォールバック: 通常の関数呼び出し
4355                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, /*is_inc=*/ true, /*is_post=*/ false)
4370            }
4371            ExprKind::PreDec(inner) => {
4372                self.build_inc_dec_syn_expr(inner, info, /*is_inc=*/ false, /*is_post=*/ false)
4373            }
4374            ExprKind::PostInc(inner) => {
4375                self.build_inc_dec_syn_expr(inner, info, /*is_inc=*/ true, /*is_post=*/ true)
4376            }
4377            ExprKind::PostDec(inner) => {
4378                self.build_inc_dec_syn_expr(inner, info, /*is_inc=*/ false, /*is_post=*/ 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                        // `.is_null()` をくっつける際は受け手側を括弧で囲む。
4394                        // c_str が `*x` のような単項式の場合 `!*x.is_null()` が
4395                        // `!*(x.is_null())` と解釈されるため。
4396                        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                // MUTABLE_PTR パターン → 内部式に変換
4409                if let Some(init_expr) = self.detect_mutable_ptr_pattern(compound) {
4410                    return self.build_syn_expr(init_expr, info);
4411                }
4412                // 通常の statement expression: Rust のブロック式として出力。
4413                // 旧パスの実装と同じ部分文字列構築 + syn::parse_str だが、
4414                // 内部の式は build_expr_string (build_syn_expr 経由) を通る。
4415                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                                // 空文を push すると join で `;;` になる
4428                                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            // CompoundLit / 未対応バリアント: 0 を返してエラーを記録。
4460            // 旧パスでも `/* TODO */` マーカーで生成コードが壊れる挙動だったため、
4461            // 体感的には同等。実用上 macro_bindings.rs にはほぼ現れない。
4462            _ => {
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    /// 関数引数を文字列に変換(macro/inline 統一版)
4473    ///
4474    /// expr_to_rust_arg 相当の処理を build_syn_expr ベースで行う。
4475    fn build_arg_string_unified(&mut self, arg: &Expr, info: Option<&MacroInferInfo>,
4476                                  callee: Option<InternedStr>, arg_index: usize) -> String {
4477        // macro: literal string パラメータ変換
4478        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                // callee の期待型が分かればそれに cast する
4487                // (memCHRs → libc::memchr の *const c_void 等。GH #15)。
4488                // 不明時は従来どおり *const c_char
4489                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        // null pointer 変換
4501        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        // bool パラメータ変換
4512        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        // 式の生成
4523        let mut syn_expr = self.build_syn_expr(arg, info);
4524        // 整数幅キャスト / SV subtype キャストを syn レベルで挿入
4525        // (文字列 "as type" の優先順位崩壊を防止)
4526        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                // C 文字列リテラル (`c"..."`, &CStr 型) を callee の `*const c_char` 等
4533                // に変換する際に `.as_ptr()` を付加。これを忘れると
4534                // `expected *const i8, found &CStr` エラーになる。
4535                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    /// 引数のキャスト挿入を syn::Expr レベルで実施。
4547    /// 旧パスの `cast_integer_arg_if_needed` (文字列ベース) と論理は同等だが、
4548    /// `as` 演算子の優先順位崩壊を起こさない。
4549    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            // enum → integer キャスト(actual が Rust enum で expected が整数型)
4554            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            // ポインタ型のサブタイプ変換 (e.g., *mut GV → *mut SV)
4569            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                // `*mut c_void` 受け取り: libc の memset/memcpy/memcmp 等は
4582                // `*mut c_void` / `*const c_void` を取るが、呼出側は
4583                // `*mut c_char` や `*mut T` を渡すことが多い。raw pointer
4584                // の as-cast はいつでも合法なので、void pointer への変換を
4585                // 汎用的に許可する。
4586                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                // const/mut のみ違い、または inner 別名違い(c_char≡i8 等)
4592                // の自動キャスト。Rust は単一レベルの `*mut T → *const T` を
4593                // 自動強制するため、その場合だけ cast を挿入しない。
4594                // ネストした二重ポインタの const 違い(例: `*mut *mut T`
4595                // → `*mut *const T`)は強制されないので cast が必要。
4596                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                    // 内側まで完全一致(文字列レベル)か
4602                    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        // actual 不明 + expected が SV ポインタ → 関数呼び出し風なら as キャスト
4615        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    /// 関数ポインタフィールド呼び出しを検出し、
4632    /// `<receiver>.<field>.unwrap_unchecked()(args)` 形式の `syn::Expr` を構築する。
4633    ///
4634    /// `_XPVCV_COMMON` の `xcv_xsub` や `PerlInterpreter` の `Ilockhook` のような
4635    /// `Option<unsafe extern "C" fn(...)>` フィールドを呼び出すパターンに対応する。
4636    /// 検出条件:
4637    ///
4638    /// 1. callee が `Member` または `PtrMember` アクセスである
4639    /// 2. そのフィールドが「関数ポインタ」と判定できる
4640    ///    - 第一に共通フィールドマクロ(`_XPVCV_COMMON` 等)由来の canonical
4641    ///      type で判定(C ソース由来)
4642    ///    - フォールバックとして bindings.rs 由来の `field_type_map` で判定
4643    ///      (文字列ヒューリスティク: `fn(` を含む)
4644    ///
4645    /// 当てはまらなければ `None` を返し、呼び出し側は通常の Call 生成パスへ進む。
4646    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        // 第一: 共通フィールドマクロ由来の canonical type で判定
4660        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        // フォールバック: bindings.rs 側の型を見て fn(...) 形式なら fn ポインタとみなす。
4666        // bindgen 出力では Option<unsafe extern "C" fn(...)> 形式になるため
4667        // "fn(" を含むかでヒューリスティック判定。フィールドの直接の型が
4668        // typedef(例: `share_proc_t`)の場合は RustDeclDict.types で解決する。
4669        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        // <receiver>.<field> までを syn::Expr で組む
4690        let field_access = self.build_syn_expr(func, info);
4691        // .unwrap_unchecked() を挟む(bindgen の Option<fn> をはがす)
4692        let callee = method_call(field_access, "unwrap_unchecked", vec![]);
4693
4694        // 引数: 既存ヘルパで構築(callee 名なし → 型ベース cast は無効)
4695        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    /// lvalue 用の syn::Expr を構築(MacroCall/Call の展開対応)
4711    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    /// `Pre/PostInc/Dec` の「lv を 1 つ増減する」代入式と lvalue を構築。
4728    /// 値が要らない文位置では pre/post の区別が消えるため、step だけを使う。
4729    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            // lv = lv.wrapping_add(1)  または wrapping_sub
4737            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    /// `Pre/PostInc/Dec` を syn::Expr で構築。
4752    /// 旧パス `expr_to_rust_ctx` の対応 arm(rust_codegen.rs の PreInc 〜 PostDec)と同等。
4753    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 _t = lv; <step>; _t }
4760            let save = let_stmt("_t", lv.clone());
4761            block_with_value(vec![save, step_stmt], ident_expr("_t"))
4762        } else {
4763            // { <step>; lv }
4764            block_with_value(vec![step_stmt], lv)
4765        }
4766    }
4767
4768    /// 文位置の `Pre/PostInc/Dec` を step 代入文だけで出力する。
4769    /// block_with_value 形 `{ *lv -= 1; *lv }` を文として出すと末尾の
4770    /// 単項式が unused_must_use に触れるため (Perl_cx_popformat 等)。
4771    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    /// 式を文位置で出力する共通経路。代入・増減式は値を返さない文形式に
4779    /// 落とす (stmt_to_rust / stmt_to_rust_inline / for の step 部で共用)。
4780    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    /// `Assign` を syn::Expr で構築。
4796    /// 旧パス `expr_to_rust_ctx` の Assign arm(rust_codegen.rs:4380 周辺)と同等。
4797    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        // RHS の構築(null リテラル特別扱い + プレーン Assign の整数幅キャスト)
4804        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            // プレーン Assign のみ: LHS 型に合わせて整数幅キャスト挿入
4819            if op == AssignOp::Assign {
4820                // 整数リテラル 0/1 を float LHS に代入 → `0.0` / `1.0` に変換
4821                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                        // ポインタ const/mut 不一致 → LHS 型に明示キャスト
4842                        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                        // SV サブタイプ / void ポインタ間の変換
4848                        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        // ビットフィールドセッター: LHS が `.getter()` 形式の MethodCall
4861        // (bitfield_methods 由来)だった場合、`set_getter(val)` 呼び出しに
4862        // 書き換える。`a.f() = v` は E0070 (invalid lvalue) になるため。
4863        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                        // setter が期待する型 (bitfield getter の戻り値型)
4870                        // に RHS を cast する。bool や違う整数幅で渡される
4871                        // ケースに対応 (`set_op_moresib(bool)` 等の E0308)。
4872                        let arg_val = if let Some(dict) = self.rust_decl_dict {
4873                            // bitfield_method_types: (struct, method) → ret_ty
4874                            // struct 名が不明なケースは任意の一致で決める
4875                            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        // op に応じた文を構築し、ブロックでラップ
4899        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                    // lv = lv.wrapping_add(r as usize);
4906                    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                // 整数幅が異なる場合 RHS を LHS 型にキャスト。
4917                // RHS が enum (Named) の場合も LHS 整数型へキャストする
4918                // (Rust enum は nominal 型で `|=` 等が直接働かない)。
4919                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                        // RHS が enum 型で LHS が整数 → `r as <lhs-int>`
4934                        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    /// lvalue 用の文字列を構築(`build_lvalue_syn_expr` の文字列化版)
4961    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    /// build_syn_expr + type_hint 適用(generate_macro のトップレベル用)
4967    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    // ================================================================
4987    // 統一文変換 (macro/inline 共通)
4988    // ================================================================
4989
4990    /// return 文を syn::Expr ベースで構築(macro/inline 統一)
4991    ///
4992    /// 整数幅キャストや bool 変換を syn::Expr レベルで挿入することで、
4993    /// 文字列ベースの `(rhs as ty)` フォーマットが `normalize_parens` で
4994    /// 括弧を剥がされて優先順位が崩れる問題(`a & b as u8` 等)を回避する。
4995    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    /// 返り値式の型キャストを syn::Expr レベルで挿入(必要なら)。
5023    /// `cast_return_expr_if_needed_unified` の syn 版。
5024    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        // enum → integer 戻り値キャスト
5031        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        // ポインタ戻り値: inner が Rust 上 compatible(c_char≡i8 等)だが文字列
5042        // 表現が違う場合は return 型に合わせて as cast を入れる。
5043        // const/mut 違いも同時に吸収する。
5044        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    /// 代入文を構築(macro/inline 統一、文コンテキスト用)
5053    ///
5054    /// LHS (`l`) と RHS (`r`) は両方とも syn::Expr 経由でビルドし、
5055    /// 整数幅キャストや `wrapping_add` の `as usize` も `cast_syn_expr` で挿入する。
5056    /// 文字列レベルで `as` を挿入する旧経路は優先順位崩壊を起こすため使わない。
5057    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        // RHS の syn::Expr を組み立てる(null リテラル特別扱い + 必要に応じてキャスト)
5063        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            // 整数幅キャスト
5075            if *op == AssignOp::Assign {
5076                // 整数リテラル 0/1 を float LHS に代入 → `0.0` / `1.0`
5077                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                        // enum → integer 代入キャスト
5090                        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                            // 代入では isize/i64 や usize/u64 を区別する(Rust 的に別型)。
5096                            // integer_types_compatible の緩い判定は演算側で使用。
5097                            if nl != nr {
5098                                r_syn = cast_syn_expr(r_syn, nl);
5099                            }
5100                        }
5101                        // ポインタ const/mut 不一致、あるいは inner 別名違い
5102                        // (c_char≡i8 等の Rust レベル同型)→ LHS 型に明示 cast
5103                        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                        // SV サブタイプ / void ポインタ間の変換
5112                        // (*sv_).sv_any = <XPVIV *> を受け入れるため)
5113                        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                        // RHS が enum で LHS が整数 → `r as <lhs-int>`
5132                        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    /// 式を文字列に変換(syn::Expr 経由で生成)
5169    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    /// 文を Rust コードに変換(マクロ用)— 統一ヘルパーに委譲
5175    fn stmt_to_rust(&mut self, stmt: &Stmt, info: &MacroInferInfo) -> String {
5176        match stmt {
5177            Stmt::Expr(Some(expr), _) => {
5178                // 代入式・増減式は inline 経路 (stmt_to_rust_inline) と同様、
5179                // 値を返さない文形式で出力する。block_with_value 形
5180                // `{ lv op= r; lv }` を文位置に出すと末尾式が
5181                // unused_must_use 等の lint に触れるため
5182                self.expr_stmt_string(expr, Some(info), "")
5183            }
5184            // 空文 (空マクロ消去後の残骸) は出力しない。";" を返すと
5185            // 呼び出し側の join で `;;` (redundant_semicolons) になる
5186            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    /// TypeName を Rust 型文字列に変換
5194    fn type_name_to_rust(&mut self, type_name: &crate::ast::TypeName) -> String {
5195        // decl_specs_to_rust でベース型を取得(プリミティブ型も正しく変換)
5196        let base_type = self.decl_specs_to_rust(&type_name.specs);
5197
5198        // 宣言子からポインタ/配列/関数を適用
5199        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        // C の const 修飾子(例: const char*)を Rust の *const に反映
5206        // 最も内側のポインタを *const にする
5207        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    /// DeclSpecs を Rust 型文字列に変換
5217    fn decl_specs_to_rust(&mut self, specs: &DeclSpecs) -> String {
5218        // typedef 名を優先
5219        for spec in &specs.type_specs {
5220            if let TypeSpec::TypedefName(name) = spec {
5221                // 型パラメータなら generic 名に置換
5222                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                // 未定義型名の検出
5227                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        // 基本型をチェック
5235        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    /// 派生型を型に適用(関数ポインタを含む完全な処理)
5317    fn apply_derived_to_type(&mut self, base: &str, derived: &[DerivedDecl]) -> String {
5318        // Function を探す
5319        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                // Function の直前が Pointer なら関数ポインタ
5326                let is_fn_pointer =
5327                    idx > 0 && matches!(derived[idx - 1], DerivedDecl::Pointer(_));
5328
5329                // 戻り値型の派生(Function と fn ptr Pointer を除く)
5330                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                // パラメータリストを生成(型のみ、名前なし)
5335                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                // 関数型を生成
5343                let fn_type =
5344                    format!("unsafe extern \"C\" fn({}) -> {}", params_str, return_type);
5345
5346                // 関数ポインタの場合は Option でラップ(NULL 許容)
5347                if is_fn_pointer {
5348                    return format!("Option<{}>", fn_type);
5349                }
5350                return fn_type;
5351            }
5352        }
5353
5354        // 通常の型変換(Function を含まない場合)
5355        self.apply_simple_derived(base, derived)
5356    }
5357
5358    /// 単純な派生型の適用(Pointer と Array のみ)
5359    fn apply_simple_derived(&self, base: &str, derived: &[DerivedDecl]) -> String {
5360        self.apply_simple_derived_with_specs_const(base, derived, false)
5361    }
5362
5363    /// 派生型を適用(specs の const 情報を考慮)
5364    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                    // void ポインタの場合は c_void を使用
5371                    if result == "()" {
5372                        result = "c_void".to_string();
5373                    }
5374                    // C の "const T *p": specs.is_const が pointee const を表す
5375                    // C の "T * const p": quals.is_const はポインタ自体の const (Rust では *mut)
5376                    // ただし "const T * const p" は両方 const → *const
5377                    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                    // void 配列の場合は c_void を使用
5391                    if result == "()" {
5392                        result = "c_void".to_string();
5393                    }
5394                    if let Some(ref size_expr) = arr.size {
5395                        // 定数サイズ配列
5396                        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                    // この関数では Function は処理しない(apply_derived_to_type で処理)
5407                }
5408            }
5409        }
5410        result
5411    }
5412
5413    /// ParamDecl から型のみを取得(名前なし)
5414    fn param_type_only(&mut self, param: &ParamDecl) -> String {
5415        let ty = self.decl_specs_to_rust(&param.specs);
5416        if let Some(ref declarator) = param.declarator {
5417            // specs の const 修飾子 (`const U8 *`) をポインタ const として
5418            // 反映する。apply_derived_to_type は常に specs_is_const=false で
5419            // 呼び出すため、ここで補正する。
5420            self.apply_simple_derived_with_specs_const(&ty, &declarator.derived, param.specs.qualifiers.is_const)
5421        } else {
5422            ty
5423        }
5424    }
5425
5426    /// inline 関数を生成(self を消費)
5427    pub fn generate_inline_fn(mut self, name: crate::InternedStr, func_def: &FunctionDef) -> GeneratedCode {
5428        let name_str = self.interner.get(name);
5429
5430        // Phase 2 (InlineFnDict::analyze_local_usage) で計算済みの
5431        // 名前使用解析を読む。テスト等で未設定の場合のみその場で計算する。
5432        // ネストした compound 内の宣言や Switch/Label も走査済みなので、
5433        // ループ内再代入の E0384 (GH #16) をここで解消する
5434        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        // mut ローカル変数名と未使用パラメータを保存
5441        // (decl_to_rust_let / param_decl_to_rust で使用)
5442        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 &param_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        // パラメータリストを取得
5461        let params_str = self.build_fn_param_list(&func_def.declarator.derived, &mut_params);
5462
5463        // 戻り値の型を取得(基本型)
5464        let return_type = self.decl_specs_to_rust(&func_def.specs);
5465
5466        // declarator の派生型(ポインタなど)を適用(Function を除く)
5467        // 例: HEK * func(...) の場合、derived = [Pointer, Function]
5468        //     戻り値型は HEK に Pointer を適用して *mut HEK になる
5469        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        // パラメータの型情報を収集 + ローカルスコープに登録
5477        for d in &func_def.declarator.derived {
5478            if let DerivedDecl::Function(param_list) = d {
5479                for p in &param_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        // 本体のローカル変数宣言もスコープに追加(ネストした compound、
5492        // StmtExpr、for ループ初期化、すべての block レベルを再帰走査)
5493        self.collect_local_names_recursive(&func_def.body);
5494
5495        // THX 依存性を判定(非 threaded では常に false)
5496        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        // AST ダンプ(デバッグ用)
5501        self.dump_ast_comment_for_body(name_str, &func_def.body);
5502
5503        // ドキュメントコメント
5504        self.writeln(&format!("/// {}{} - inline function", name_str, thx_info));
5505        self.writeln("#[inline]");
5506        self.writeln("#[allow(unsafe_op_in_unsafe_fn)]");
5507
5508        // 関数定義
5509        self.writeln(&format!("pub unsafe fn {}({}) -> {} {{", name_str, params_str, return_type));
5510
5511        // unsafe 操作(関数呼び出し or デリファレンス)を含む場合のみ unsafe ブロックを生成
5512        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    /// DerivedDecl から関数パラメータリストを構築
5531    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                // C の `fn(void)` は「引数なし」の同義。単独の void パラメータは
5535                // Rust の 0 引数に変換する(そうしないと `fn(_: ())` となり呼出側
5536                // が 0 引数と食い違って E0061 を起こす)。
5537                if is_void_only_param_list(&param_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    /// inline 関数が THX 依存かどうかを判定
5557    ///
5558    /// 最初のパラメータが `my_perl` という名前であれば THX 依存とみなす。
5559    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    /// ParamDecl を Rust パラメータ宣言に変換
5577    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            // 未使用パラメータは `_` prefix (unused_variables 対策、GH #22)。
5583            // 本体に参照が無いことが保証されるので束縛名だけ変えれば良い
5584            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(&param.specs);
5592
5593        // ポインタ派生型を適用(specs の const を考慮)
5594        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        // current_param_types に登録(型推論で使用)
5601        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    /// Declaration を Rust の let 宣言に変換
5615    fn decl_to_rust_let(&mut self, decl: &Declaration, indent: &str) -> String {
5616        let mut result = String::new();
5617
5618        // 基本型を取得
5619        let base_type = self.decl_specs_to_rust(&decl.specs);
5620
5621        // 各宣言子を処理
5622        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            // 派生型(ポインタなど)を適用
5628            let ty = self.apply_derived_to_type(&base_type, &init_decl.declarator.derived);
5629
5630            // 初期化子
5631            if let Some(ref init) = init_decl.init {
5632                match init {
5633                    Initializer::Expr(expr) => {
5634                        // 宣言型と式の推論型が異なる整数型なら as キャストを syn レベルで挿入。
5635                        // 文字列ベースの `({} as {})` は normalize_parens に剥がされて
5636                        // `a as u32 & b as u8` の優先順位崩壊を起こすため、syn::Expr で
5637                        // 構築して expr_to_string に括弧の挿入を任せる。
5638                        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                        // ポインタの const/mut 不一致は init 側に明示キャストを挿入する。
5651                        // 旧実装は宣言型を *const に書換えていたが、それだと以降の
5652                        // 代入で *mut 型が期待されるマクロ引数などで破綻する。
5653                        // 例: `let s: *mut U8 = s0;` (s0: *const U8) → `s0 as *mut U8`
5654                        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                        // null リテラルの場合は型推論に任せて std::ptr::null_mut()
5667                        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                        // 初期化リストは複雑なので TODO
5679                        result.push_str(&format!("{}let {}: {} = /* init list */;\n", indent, name, ty));
5680                    }
5681                }
5682            } else {
5683                // 初期化子なし。Rust の deferred initialization (`let x: T;`)
5684                // で「宣言 → 後で代入」は合法だが、最初の代入より前に
5685                // アドレスを取られる out-param パターンは E0381 になるため
5686                // zeroed 初期化に切り替える (GH #23)
5687                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    /// 複合文を文字列として生成
5705    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    /// 文を Rust コードに変換(インライン関数用)
5726    fn stmt_to_rust_inline(&mut self, stmt: &Stmt, indent: &str) -> String {
5727        match stmt {
5728            Stmt::Expr(Some(expr), _) => {
5729                // 代入式・増減式は値を返さない形式で出力(統一ヘルパー使用)
5730                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                // 条件が既に bool なら != 0 を追加しない
5738                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                // 条件が既に bool なら != 0 を追加しない。
5774                // if 側 (:5822) と同様 normalize_parens で外側括弧を除去しないと
5775                // `while (cond)` が unused_parens になる
5776                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                // 初期化部分
5789                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                // ループ部分
5803                if let Some(cond_expr) = cond {
5804                    let cond_str = self.build_expr_string(cond_expr, None);
5805                    // 条件が既に bool なら != 0 を追加しない (外側括弧除去は While と同様)
5806                    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                // ループ本体
5815                result.push_str(&self.stmt_to_rust_inline(body, &body_indent));
5816                result.push_str("\n");
5817
5818                // ステップ部分 (i++ 等は値を返さない文形式で)
5819                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                // do { ... } while (0) パターンは一度だけ実行される loop として出力
5830                // これにより内部の break; が正しく動作する
5831                if is_zero_constant(cond) {
5832                    // 内部 body に `break;` が含まれなければ単なる block で十分。
5833                    // STMT_START/STMT_END 由来なら break なしのケースがほとんど。
5834                    // その方が `loop {...break;}` の `()`-型による tail 型不一致
5835                    // (fn が usize 等を返す場合の E0308) を避けられる。
5836                    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                // 一般的な do-while 文: loop { body; if !cond { break; } }
5854                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                // bool 式なら !(cond)、そうでなければ cond == 0
5860                // `!{}` 直付けだと `!a < b` のように優先順位で Lt が bind され、
5861                // `cannot apply ! to pointer` 等の誤生成になる。
5862                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                // body から Case/Default を収集
5877                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                // Switch 外で Case が出現した場合(通常は Switch 内で処理される)
5884                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    /// Switch 文の body から Case/Default を収集して match アームを生成
5920    fn collect_switch_cases(&mut self, stmt: &Stmt, indent: &str, result: &mut String) {
5921        // パス1: case/default とそれに続く文を収集
5922        struct SwitchCase {
5923            patterns: Vec<String>,   // case 式のリスト(複数 case ラベル対応)、空 = default
5924            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        // Compound の中身をフラット化して処理
5932        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        // ネストされた case/default を展開して patterns と最終的な stmt を取得
5941        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                    // default に到達
5949                    (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                            // ネストされた case をフラット化
5964                            let mut patterns: Vec<&Expr> = vec![case_expr];
5965                            let (final_stmt, has_default) = flatten_case_chain(case_stmt, &mut patterns);
5966
5967                            // パターンは enum バリアントをフルパスで出力
5968                            let pattern_strs: Vec<String> = patterns.iter()
5969                                .map(|e| self.expr_to_rust_pattern(e))
5970                                .collect();
5971
5972                            // final_stmt が Break の場合はスキップ(Rust の match は break 不要)
5973                            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                            // ネストされた case をフラット化
5986                            let mut patterns: Vec<&Expr> = Vec::new();
5987                            let (final_stmt, _) = flatten_case_chain(default_stmt, &mut patterns);
5988
5989                            // パターンは enum バリアントをフルパスで出力
5990                            let pattern_strs: Vec<String> = patterns.iter()
5991                                .map(|e| self.expr_to_rust_pattern(e))
5992                                .collect();
5993
5994                            // final_stmt が Break の場合はスキップ(Rust の match は break 不要)
5995                            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                            // Rust の match はフォールスルーしないので break は不要
6008                            // スキップする
6009                        }
6010                        other => {
6011                            // 直前の case に追加
6012                            if let Some(last) = cases.last_mut() {
6013                                last.body_stmts.push(self.stmt_to_rust_inline(other, &body_indent));
6014                            }
6015                            // case がまだない場合は無視
6016                        }
6017                    }
6018                }
6019                BlockItem::Decl(decl) => {
6020                    self.collect_decl_types(decl);
6021                    // 宣言は直前の case に追加
6022                    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        // パス2: 収集した cases から match アームを生成
6030        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                    // case A: case B: default: ... のパターン
6037                    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        // C の switch は default が無ければ該当しない値を素通しする。
6051        // Rust match は網羅性が必要なため、default 無しのケースで
6052        // `_ => {}` を自動挿入する。
6053        if !has_default {
6054            result.push_str(&format!("{}_ => {{}}\n", indent));
6055        }
6056    }
6057
6058    /// offsetof のフィールドパス式をドット区切り文字列に変換
6059    /// Ident("xnv_u") → "xnv_u"
6060    /// Member(Ident("xnv_u"), "xnv_nv") → "xnv_u.xnv_nv"
6061    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    /// match パターン用の式を Rust に変換
6077    ///
6078    /// 通常の式変換と異なり、enum バリアントをフルパスで出力する。
6079    /// Rust の match パターンでは、単純な識別子は変数束縛として扱われるため、
6080    /// enum バリアントは `crate::EnumName::VariantName` 形式で出力する必要がある。
6081    fn expr_to_rust_pattern(&mut self, expr: &Expr) -> String {
6082        match &expr.kind {
6083            ExprKind::Ident(name) => {
6084                // enum バリアントかチェック
6085                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            // 他の式は通常の変換
6094            _ => self.build_expr_string(expr, None)
6095        }
6096    }
6097}
6098
6099impl<'a, W: Write> CodegenDriver<'a, W> {
6100    /// 新しいコード生成ドライバを作成
6101    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            // デフォルトは threaded(後方互換)。`generate()` で
6124            // result.perl_build_mode から書き換える。
6125            perl_threaded: true,
6126        }
6127    }
6128
6129    /// 対象 perl が threaded かを設定
6130    pub fn with_perl_threaded(mut self, threaded: bool) -> Self {
6131        self.perl_threaded = threaded;
6132        self
6133    }
6134
6135    /// 統計情報を取得
6136    pub fn stats(&self) -> &CodegenStats {
6137        &self.stats
6138    }
6139
6140    /// 関数別の生成結果を取得 (generate() 完了後に有効)
6141    pub fn report(&self) -> &CodegenReport {
6142        &self.report
6143    }
6144
6145    /// 全体を生成
6146    // デバッグ用: ビルド時のタイムスタンプを埋め込む場合はコメントを外す
6147    // const BUILD_TIMESTAMP: &'static str = "2025-01-24T17:50:00+09:00";
6148
6149    pub fn generate(&mut self, result: &InferResult) -> io::Result<()> {
6150        // 対象 perl の threaded フラグを反映(is_thx_dependent 経路の防御的ガード)
6151        self.perl_threaded = result.perl_build_mode.is_threaded();
6152
6153        // 自動生成 struct/typedef を先に決定(known_symbols 構築前)
6154        // 実際に出力される名前のみ known_symbols に登録するため、emit を先行実施。
6155        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        // 自動生成した static 配列名を bindings_info.static_arrays / static_types に登録。
6167        // これにより codegen が `.as_ptr()` 減衰を掛けるべき配列として認識し、
6168        // 要素型 T も `(&raw const NAME) as *const T` で正しく出せる。
6169        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        // 既知シンボル集合を構築(未解決シンボル検出用)
6177        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        // 自動生成 struct の bit-field アクセサを bindings_info にマージ。
6186        // これにより `is_bitfield_method` がそれらの getter 名を認識し、
6187        // `.name` → `.name()` / `.name = val` → `.set_name(val)` の書換が効く。
6188        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        // global_const_dict 由来の static 配列は既に KnownSymbols::new 内で
6196        // 登録済みなので追加不要
6197
6198        // ヘッダーコメント
6199        writeln!(self.writer, "// Auto-generated Rust bindings")?;
6200        // デバッグ用: タイムスタンプを出力する場合はコメントを外す
6201        // writeln!(self.writer, "// Generated by libperl-macrogen (build: {})", Self::BUILD_TIMESTAMP)?;
6202        writeln!(self.writer, "// Generated by libperl-macrogen")?;
6203        writeln!(self.writer)?;
6204
6205        // use 文を出力
6206        self.generate_use_statements()?;
6207
6208        // target enum のバリアントを import
6209        self.generate_enum_imports(result)?;
6210
6211        // 自動生成 struct/union 定義を出力
6212        if !missing_structs.source.is_empty() {
6213            self.writer.write_all(missing_structs.source.as_bytes())?;
6214        }
6215
6216        // 自動生成 static const 配列を出力(事前算出済み)
6217        if !static_arrays.source.is_empty() {
6218            self.writer.write_all(static_arrays.source.as_bytes())?;
6219        }
6220
6221        // マクロの生成可能性を事前計算(inline→macro カスケード検出用)
6222        self.precompute_macro_generability(result, &known_symbols);
6223
6224        // Phase 2 の解析結果を収集(inline/macro 両方で使用)
6225        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        // inline 関数セクション
6232        if self.config.emit_inline_fns {
6233            self.generate_inline_fns(result, &known_symbols)?;
6234        }
6235
6236        // マクロセクション
6237        if self.config.emit_macros {
6238            self.generate_macros(result, &known_symbols)?;
6239        }
6240
6241        // 使用された libc 関数の use 文を出力(rustfmt が先頭に移動する)
6242        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    /// use 文を生成
6252    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    /// target enum のバリアントを import
6270    ///
6271    /// bindings.rs に存在する enum のみ import する
6272    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        // bindings.rs に存在する enum のみフィルタリング
6277        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    /// マクロの生成可能性を事前計算
6297    ///
6298    /// inline 関数生成前に呼び出し、マクロ→マクロのカスケード検査をシミュレートして
6299    /// 正常に生成可能なマクロの集合を構築する。
6300    /// inline→macro のカスケード検出に使用する。
6301    fn precompute_macro_generability(&mut self, result: &InferResult, known_symbols: &KnownSymbols) {
6302        // 対象マクロを収集
6303        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        // 依存順にソート(葉マクロ先頭)
6309        let sorted_names = self.topological_sort_macros(&macros);
6310
6311        for name in sorted_names {
6312            let info = result.infer_ctx.macros.get(&name).unwrap();
6313
6314            // apidoc_suppressed なマクロは generatable_macros に入れない
6315            // (Phase 3 の早期 SUPPRESSED 分岐で抑止される。inline→macro の
6316            //   cascade 検査が `generatable_macros` を参照するので、ここで
6317            //   除外しないと skip_codegen 対象を呼ぶ inline が誤って success
6318            //   扱いになる抜け穴ができる)
6319            if info.apidoc_suppressed {
6320                continue;
6321            }
6322
6323            // カスケード検査: called_functions が生成不可なマクロを含むか
6324            // 被呼び出し先の判定は is_unavailable_for_codegen() を使う
6325            // (= apidoc_suppressed 由来の不可も Phase 2 propagation で
6326            //   calls_unavailable に流れているはずだが、防御的に OR を取る)
6327            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            // get_macro_status + trial codegen による判定
6341            let status = self.get_macro_status(info);
6342            if status == GenerateStatus::Success {
6343                // 実際に codegen を試行して完全性を確認
6344                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    /// inline 関数セクションを生成
6358    ///
6359    /// 2パス方式:
6360    /// - Pass 1: 各 inline 関数を生成し、結果を蓄積
6361    /// - Pass 2: カスケード検査 — 生成成功した関数が失敗した inline 関数や
6362    ///   マクロを呼び出している場合、CASCADE_UNAVAILABLE に降格
6363    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        // 名前順にソート
6370        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        // 対象 inline 関数名の集合
6376        let inline_set: HashSet<InternedStr> = fns.iter().map(|(n, _)| **n).collect();
6377
6378        // Pass 1: 各 inline 関数を生成
6379        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            // apidoc skip_codegen 対象(Phase 2 で apidoc_suppressed 済)は
6393            // 早期に Suppressed。reason 文字列は apidoc_patches から取得。
6394            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            // 事前に unavailable と判定された関数はスキップ
6405            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        // Pass 1.5: successfully_generated_inlines を構築(Success のみ)
6446        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        // Pass 2: カスケード検査 — Success だが失敗した依存先を呼び出す場合は降格
6453        // InlineFnDict の called_functions を使用(ad-hoc 収集不要)
6454        // inline→inline と inline→macro の両方を検査
6455        // 繰り返し伝播(fixpoint)
6456        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                        // inline→inline: 対象 inline が生成失敗
6467                        if inline_set.contains(called) && !current_success.contains(called) {
6468                            return true;
6469                        }
6470                        // inline→macro: 対象マクロが生成不可
6471                        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        // Pass 3: 出力
6489        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                    // 原因を分類: 純粋に存在しない関数を呼ぶ (absent) と
6495                    // 推移的に unavailable な依存先を呼ぶ (cascade) を区別する。
6496                    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                    // HashSet 由来の列挙順を決定化 (run ごとのコメント揺れ防止)
6519                    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(); // 列挙順の決定化
6562                    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                        // 正常出力
6598                        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                        // カスケード降格: 呼び出し先の inline 関数が codegen 時に失敗
6604                        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(); // 列挙順の決定化
6612                        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    /// マクロセクションを生成
6632    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        // 対象マクロを収集
6639        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        // 依存順にソート(葉マクロ先頭)
6645        let sorted_names = self.topological_sort_macros(&macros);
6646
6647        // ── Phase 2 の解析結果を参照 ──
6648        // const/mut, bool 戻り値は Phase 2 (resolve_param_and_return_types) で確定済み
6649        // MacroInferInfo.const_pointer_positions, is_bool_return を参照する
6650        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        // 正常生成されたマクロを追跡
6664        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            // ── apidoc skip_codegen 対象なら早期に [CODEGEN_SUPPRESSED] ──
6670            // Phase 2 (Step 4.4) で `info.apidoc_suppressed` が立っているので
6671            // それを参照する。reason 文字列は apidoc_patches から取得。
6672            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            // ── apidoc 戻り値型 pair (カンマ式で複数値) も codegen 対象外 ──
6688            // Phase 2 (Step 4.45) で `info.pair_return` が立っている
6689            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            // ── カスケード検査 ──
6704            // called_functions のうち、生成対象だが生成に失敗した関数があれば
6705            // カスケード失敗。マクロ→マクロ依存と マクロ→inline 関数依存の両方を検査。
6706            // (uses ではなく called_functions を使う:uses はインライン展開された
6707            //   マクロも含むが、called_functions は AST 上の Call 式のみ)
6708            let unavailable_deps: Vec<String> = info.called_functions.iter()
6709                .filter(|called| {
6710                    // Case 1: マクロ→マクロ依存
6711                    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                    // Case 2: マクロ→inline 関数依存
6718                    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            // ── 既存のステータス判定と生成 ──
6736            let status = self.get_macro_status(info);
6737            match status {
6738                GenerateStatus::Success => {
6739                    // 新しい RustCodegen を使ってマクロを生成
6740                    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                        // 未解決シンボルあり:コメントアウトして出力
6754                        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                        // codegen エラー検出:コメントアウトして問題点列挙
6767                        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                        // 完全な生成:そのまま出力
6781                        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                        // 不完全な生成:コメントアウトして出力
6788                        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                    // 原因を分類: 「実在しない関数を呼ぶ」vs「推移的に
6813                    // unavailable な依存先を呼ぶ」。前者なら [CALLS_UNAVAILABLE]、
6814                    // 後者なら [CASCADE_UNAVAILABLE] を出す。
6815                    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                        // 純粋に推移依存。unavailable な依存先を列挙
6824                        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                    // コメントアウトしたコードを出力
6861                    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                    // 出力なし。require 検証用に理由だけ記録する
6880                    self.report.record_skip(self.interner.get(info.name),
6881                        "SKIP: excluded from code generation");
6882                }
6883            }
6884        }
6885
6886        Ok(())
6887    }
6888
6889    /// マクロを依存順にソート(葉マクロ先頭、循環はアルファベット順で末尾)
6890    ///
6891    /// Kahn's algorithm を使用。`info.uses` の関係から DAG を構築し、
6892    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        // 入次数マップと逆隣接リスト(dependency → dependents)を構築
6901        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                    // name が used に依存 → used から name への辺
6912                    *in_degree.entry(**name).or_insert(0) += 1;
6913                    dependents.entry(*used).or_default().push(**name);
6914                }
6915            }
6916        }
6917
6918        // 入次数 0 のマクロをキューに投入(アルファベット順で安定化)
6919        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                // 依存先の入次数を減算
6934                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                // アルファベット順で安定化
6944                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        // 残り(循環メンバー)をアルファベット順で末尾に追加
6952        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    /// カスケード依存によるコメントアウト出力
6966    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(); // 列挙順の決定化
6975        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    /// マクロを出力対象にするかどうか
6986    fn should_include_macro(&self, info: &MacroInferInfo) -> bool {
6987        // ターゲットでなければスキップ
6988        if !info.is_target {
6989            return false;
6990        }
6991
6992        // 本体がなければスキップ
6993        if !info.has_body {
6994            return false;
6995        }
6996
6997        // 関数形式マクロのみ含める(オブジェクトマクロは常にインライン展開される)
6998        info.is_function
6999    }
7000
7001    /// マクロの生成ステータスを判定
7002    fn get_macro_status(&self, info: &MacroInferInfo) -> GenerateStatus {
7003        // 利用不可関数を呼び出すマクロは CallsUnavailable
7004        if info.calls_unavailable {
7005            return GenerateStatus::CallsUnavailable;
7006        }
7007
7008        // ジェネリクス型パラメータを含むマクロは生成不可
7009        // Rust の as T キャストや T + u32 演算が不可
7010        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                // goto を含むマクロは除外
7018                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    /// パース失敗マクロをコメント出力
7038    fn generate_macro_parse_failed(&mut self, info: &MacroInferInfo) -> io::Result<()> {
7039        let name_str = self.interner.get(info.name);
7040
7041        // パラメータリストを構築
7042        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        // エラーメッセージがあれば出力
7054        if let ParseResult::Unparseable(Some(err_msg)) = &info.parse_result {
7055            writeln!(self.writer, "// Error: {}", err_msg)?;
7056        }
7057
7058        // TODO: トークン列の S 式出力(Phase 2 で詳細実装)
7059        writeln!(self.writer, "// (tokens not available in parsed form)")?;
7060        writeln!(self.writer)?;
7061
7062        Ok(())
7063    }
7064
7065    /// 利用不可関数呼び出しマクロをコメント出力
7066    fn generate_macro_calls_unavailable(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7067        let name_str = self.interner.get(info.name);
7068
7069        // パラメータリストを構築
7070        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        // THX 情報
7080        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        // 利用不可関数を特定して出力
7085        let unavailable_fns: Vec<_> = info.called_functions.iter()
7086            .filter(|&fn_id| {
7087                let fn_name = self.interner.get(*fn_id);
7088                // bindings.rs にもマクロにも存在しない関数を検出
7089                !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(); // 列挙順の決定化
7097            writeln!(self.writer, "// Unavailable: {}", unavailable_fns.join(", "))?;
7098        }
7099
7100        writeln!(self.writer)?;
7101
7102        Ok(())
7103    }
7104
7105    /// 関数が利用可能かチェック
7106    fn is_function_available(&self, fn_id: crate::InternedStr, fn_name: &str, result: &InferResult) -> bool {
7107        // マクロとして存在する場合はOK
7108        if result.infer_ctx.macros.contains_key(&fn_id) {
7109            return true;
7110        }
7111
7112        // bindings.rs に存在する場合はOK
7113        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        // インライン関数として存在する場合はOK
7120        if result.inline_fn_dict.get(fn_id).is_some() {
7121            return true;
7122        }
7123
7124        // ビルトイン関数リスト(macro_infer.rs と同じ)
7125        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    /// 型推論失敗マクロをコメント出力
7168    fn generate_macro_type_incomplete(&mut self, info: &MacroInferInfo, result: &InferResult) -> io::Result<()> {
7169        let name_str = self.interner.get(info.name);
7170
7171        // パラメータリストを構築
7172        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        // 型推論状態を出力
7184        writeln!(self.writer, "// Args status: {:?}, Return status: {:?}",
7185            info.args_infer_status, info.return_infer_status)?;
7186
7187        // 型付 S 式を出力
7188        writeln!(self.writer, "// Typed S-expression:")?;
7189        self.write_typed_sexp_comment(info, result)?;
7190
7191        writeln!(self.writer)?;
7192        Ok(())
7193    }
7194
7195    /// 型付 S 式をコメントとして出力
7196    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    /// 式の S 式をコメントとして出力
7216    fn write_expr_sexp_comment(&mut self, expr: &Expr, info: &MacroInferInfo, prefix: &str) -> io::Result<()> {
7217        // 簡易的な S 式出力
7218        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        // 型情報を追加
7225        let sexp_str = String::from_utf8_lossy(&buf);
7226        let type_info = self.get_expr_type_info(expr, info);
7227
7228        // 各行にプレフィックスを付けて出力
7229        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    /// 文の S 式をコメントとして出力
7240    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    /// 式の型情報を取得
7256    fn get_expr_type_info(&self, expr: &Expr, info: &MacroInferInfo) -> String {
7257        // TypeEnv から型制約を取得
7258        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        // Display にも名前と理由が現れる
7301        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(),        // emitted → OK
7320            "CvSTART".to_string(),       // skipped → 違反
7321            "NoSuchFunction".to_string(), // 不在 → 違反
7322        ];
7323        let err = report.check_required(&required).unwrap_err();
7324        assert_eq!(err.violations.len(), 2);
7325    }
7326}