---
title: 'EvoC2Rust: Skeleton-Guided C-to-Rust'
url: https://www.emergentmind.com/topics/evoc2rust
type: topic
---

# EvoC2Rust: Skeleton-Guided C-to-Rust

Searching arXiv for EvoC2Rust and closely related C-to-Rust translation work.
EvoC2Rust is a skeleton-guided framework for project-level C-to-Rust translation that seeks to convert entire C projects into equivalent Rust ones by first generating a compilable Rust skeleton, then incrementally replacing type-checked stubs with translated function bodies, and finally repairing compilation errors through LLM- and static-analysis-driven refinement [2508.04295]. It is positioned between rule-based translators, which generally preserve buildability at the cost of heavy `unsafe` and low idiomaticity, and pure LLM pipelines, which are more expressive but tend to break under project-wide dependency, signature, and context-management pressures.

## 1. Research setting and intellectual context

EvoC2Rust emerged in a research landscape shaped by two converging observations. First, Rust offers compile-time ownership and borrowing guarantees while remaining performance-competitive with C and C++; a benchmark study on everyday routines reported overall performance similar to C++, with only a minor disadvantage overall and some routines in which Rust was slightly faster [2209.09127]. Second, C-to-Rust migration had already split into sharply different methodological camps: rule-based ownership lifting, manual or human-guided semantic lifting, and partial elimination of specific unsafe constructs such as unions [2303.10515][2411.14174][2408.11418].

Earlier work exposed the strengths and limitations that EvoC2Rust explicitly tries to reconcile. Crown centered translation around static ownership analysis and safe retyping of C pointers, achieving large-scale conversion by inferring ownership models over access paths [2303.10515]. A user study on human C-to-Rust translation showed that people often depart radically from line-by-line conversion, instead using zero-cost abstractions, semantic data-type lifting, and specialized restructuring strategies to obtain safe Rust where automatic tools struggled [2411.14174]. Work on union translation demonstrated that one important residual unsafe feature in C2Rust-generated code could be attacked by identifying C tag fields and replacing unions with Rust tagged unions [2408.11418]. EvoC2Rust’s contribution is to treat these sorts of mappings not as isolated post-processing passes, but as ingredients in a project-scale, LLM-assisted framework that retains a globally consistent scaffold [2508.04295].

## 2. Skeleton-guided project translation

The framework’s defining architectural move is the construction of a compilable Rust “skeleton” before function-body translation begins [2508.04295]. EvoC2Rust parses the C project with Tree-sitter, extracting filenames, `#include` relations, macro definitions, structs, typedefs, global variables, function prototypes and definitions, a call graph, and a declaration-to-file map. This metadata is then converted into a Rust crate layout with modules, `pub use` re-exports, translated definitions, and type-checked function stubs whose bodies are initially `unimplemented!()`.

This skeleton serves several roles simultaneously. It fixes inter-module structure early, so later translation steps do not have to rediscover symbol visibility or crate topology. It also fixes function signatures in advance, which prevents later LLM passes from drifting into incompatible local APIs. Most importantly, it transforms a project-wide dependency problem into a sequence of local body-replacement problems: every callee already exists as a typed Rust symbol, so a translated function body only needs to satisfy its predeclared contract rather than inventing one.

The original paper describes three evolutionary stages. In the first, the system decomposes the C project into functional modules, uses a feature-mapping-enhanced LLM to transform definitions and macros, and generates type-checked function stubs that form the compilable skeleton. In the second, it incrementally translates functions by replacing the corresponding stub placeholders. In the third, it repairs compilation errors by integrating LLM-based and static-analysis-based fixes [2508.04295]. The term “skeleton-guided” therefore refers not merely to placeholder generation, but to a global consistency mechanism that constrains all later local edits.

## 3. Feature mappings and the translation substrate

EvoC2Rust’s LLM is not prompted in a generic “translate C to Rust” mode. Instead, it is augmented with explicit feature mappings in seven categories: types, type conversion, macros/functions, syntax structures, operators, global variables, and variadic arguments [2508.04295]. These mappings are implemented partly as promptable transformation patterns and partly as a Rust helper library that gives the model safe target constructs for otherwise difficult C idioms.

Type mappings include `Array<T, N>` for fixed-size arrays and `Ptr<T>` for pointer-like behavior. Global state is wrapped with `Global<T>` and `global!()`, replacing direct mutable globals with a safe wrapper based on `Mutex<T>`. Syntax structures that do not map cleanly to native Rust control flow are encoded as macros such as `c_for!`, `c_do!`, and `c_switch!`, allowing the generated Rust to preserve C control semantics without forcing the model to simulate them ad hoc. Operator-level mappings include `c_ref!()` for address-of, `c_sizeof!` and `c_sizeofval!`, and support for `++` and `--`. Variadic interfaces are normalized via `VaList<'a>` and helpers such as `va_format!()`.

These mappings are retrieved dynamically. The framework embeds both the input snippet and a library of transformation patterns, computes similarity with BGE-M3, and injects the top-ranked patterns into the translation prompt [2508.04295]. The effect is to narrow the LLM’s search space toward prevalidated Rust encodings of hard C features. A representative case is `snprintf`, whose C variadic interface is translated into a Rust function over `Ptr<u8>`, `usize`, `Ptr<u8>`, and `VaList`, with the formatting logic delegated to `va_format!()` and buffer writes expressed through the pointer abstraction rather than direct raw-pointer manipulation.

This design suggests that EvoC2Rust is less a monolithic translator than a constrained generation environment. The LLM remains generative, but it is steered toward a controlled Rust dialect that emulates C semantics through safe abstractions. That is a plausible reason why the framework reports high safety while still preserving substantial syntactic and semantic fidelity, although the paper itself frames this primarily as “feature-mapping-enhanced” prompting rather than as a separate formal intermediate language [2508.04295].

## 4. Evolutionary repair and compilation-driven refinement

After stub replacement, EvoC2Rust runs a three-stage repair chain: bracket repair, rule-based repair, and LLM refinement [2508.04295]. Bracket repair is an LLM pass specialized for mismatched delimiters and similar syntax-level failures, explicitly instructed not to modify unrelated code. Rule-based repair then applies targeted transformations such as adjusting derives, removing redundant `cast()` calls, or rewriting specific indexing patterns that trigger borrow-checker failures. A final LLM refinement pass uses compilation diagnostics to repair remaining type and semantic inconsistencies while respecting the fixed skeleton signatures.

The repair loop is compilation-driven. After each candidate change, the code is recompiled; only repairs that reduce the error count are retained, and the process stops when no improvement occurs or a small iteration budget is exhausted. This makes the compiler the principal arbiter of local correctness, while the skeleton remains the arbiter of global consistency.

The importance of these stages is visible in the reported ablations. Removing feature mapping causes the project-level incremental compilation rate on industrial data to drop from 93.84% to 56.67%, and the module-level test pass rate to fall from 89.53% to 30.27% [2508.04295]. When both mapping and repairs are removed, SafeRate drops from about 97.4% to 82.43. These results indicate that EvoC2Rust’s gains do not come from skeleton construction alone; they depend on the combination of mapped abstractions and iterative repair. The framework’s “evolutionary augmentation” is therefore best understood as staged accumulation of correctness constraints over a compilable scaffold rather than as an evolutionary algorithm in the population-based sense.

## 5. Evaluation methodology and reported results

The framework is evaluated on two benchmark families [2508.04295]. Vivo-Bench contains 19 open-source projects with 38 files, 80–917 LOC per project, 200 functions, 29 macros, 95 definitions, and 113 test cases. C2R-Bench contains six industrial projects from Huawei—`avl`, `bzp`, `md5`, `sha256`, `rapidlz`, and `cmptlz`—with 63 files, 8,170 LOC, 288 functions, 346 macros, 63 definitions, and 222 test cases.

At project level, the paper reports three principal metrics. `ICompRate` is the incremental compilation pass rate. `AccRate` is a line-acceptance measure reported as precision and recall against a manually corrected reference translation. `SafeRate` is the percentage of memory-safe statements. EvoC2Rust reports the following project-level results:

| Dataset | ICompRate | AccRate (P/R) | SafeRate |
|---|---:|---:|---:|
| Vivo-Bench | 100 | 99.83 / 99.86 | 98.00 |
| C2R-Bench | 93.84 | 97.56 / 97.34 | 97.41 |

Against LLM-based baselines, the paper reports average improvements of 17.24% in syntax accuracy and 14.32% in semantic accuracy, and against rule-based tools it reports a 96.79% higher code safety rate [2508.04295]. On Vivo-Bench, EvoC2Rust reaches 100 `ICompRate`, 99.83/99.86 `AccRate`, and 98.00 `SafeRate`, while on C2R-Bench it reports 93.84 `ICompRate`, 97.56/97.34 `AccRate`, and 97.41 `SafeRate`.

At module level, the framework uses `FCompRate`, the fill-in compilation pass rate for translated functions inserted into the skeleton, and `TestRate`, the fraction of such functions that pass tests. With DeepSeek-V3, EvoC2Rust reaches 99.07 `FCompRate` and 98.50 `TestRate` on Vivo-Bench, and an overall 92.25 compilation and 89.53 test pass rate on the six industrial projects [2508.04295]. The per-project industrial `TestRate` values are 92.53 for `avl`, 92.55 for `bzp`, 86.21 for `md5`, 100 for `sha256`, 92.11 for `rapidlz`, and 86.35 for `cmptlz`. With Qwen3-32B, the overall industrial `FCompRate` and `TestRate` fall to 80.63 and 77.91, which the paper uses to argue that the framework remains functional with smaller models but benefits materially from stronger ones.

The paper also reports that longer functions remain harder: with DeepSeek-V3, module-level test pass rate decreases from about 97.46% for shorter functions to about 81.13% for the longest category, while with Qwen3-32B the drop is much larger, down to about 41.96% [2508.04295]. This suggests that skeleton guidance and feature mapping reduce but do not eliminate context-length and reasoning-depth effects.

## 6. Subsequent assessments, limitations, and research significance

The original paper is explicit about several limitations. Correctness is validated through benchmark tests rather than formal equivalence; the reference Rust implementations used for acceptance metrics required LLM assistance plus human correction; and the evaluated projects are single-threaded user-space C that use the standard library, not multithreaded, third-party-library-heavy, or kernel-level software [2508.04295]. The authors identify fuzzing, self-debugging, LLM agents with planning and reflection, and extension to concurrency and FFI-heavy code as future directions.

Later literature treated EvoC2Rust as an important but incomplete step in project-scale migration. ENCRUST characterized it as a project-scale system but reported that, in its Coreutils evaluation, EvoC2Rust yielded non-compiling code on all 7 programs and 0% correctness, with safety numbers only obtainable after normalizing missing functions via C2Rust output [2604.04527]. RustPrint described EvoC2Rust as a skeleton-guided framework built around a compilable Rust scaffold and iterative refinement, but reported that on eight repositories ranging from 11.4K to 83.7K LoC it failed to produce end-to-end compilable repositories under both Kimi-K2-Instruct and GPT-5.4; at the same time, the generated fragments still showed SafeRate (A/F) of 94.79/96.60 with Kimi-K2-Instruct and 95.13/96.74 with GPT-5.4 [2605.14634]. This suggests that the core idea of skeleton guidance remained valuable for local safety and modular consistency, but later repository-scale studies found that larger systems demanded stronger global coordination mechanisms such as ABI-preserving wrappers, documentation-guided planning, or richer orchestration.

In the broader history of C-to-Rust translation, EvoC2Rust occupies a transitional position. It moves beyond ownership-only or transpilation-only methods by turning abstractions such as `Ptr<T>`, `Global<T>`, `VaList`, and control-flow macros into first-class promptable targets, while also constraining generation through a compilable scaffold. It also remains more structure-preserving than later systems that perform larger architectural rewrites. A plausible implication is that its lasting significance lies less in any single benchmark number than in establishing skeleton-guided, feature-mapped, compiler-steered translation as a distinct design point in the migration literature [2508.04295].

Source: https://www.emergentmind.com/topics/evoc2rust