Skip to content

Commit 4a4af13

Browse files
fix(codegen): emit faithful Rust/C, don't run t27c optimizer on source backends (#1455)
t27c's AST optimizer corrupts the SOURCE-LEVEL output of the Rust and C backends: a reassigned mutable local (`var x = 0; ... x = a;`) loses its declaration while its uses remain (E0425), and `let` locals are const-inlined. This is the 2609-site E0425 wave observed downstream in gHashTag/tri-net. Root cause: compile_rust / compile_c ran `optimize(&mut ast, default)` (const prop + the unconditional copy-prop / dead-store passes) before emitting SOURCE code. Those passes are meant for a lowering target, not for human/rustc-facing source; rustc and the C compiler optimize the emitted code far more reliably. Fix: drop the `optimize()` call from compile_rust and compile_c and emit faithfully from the parsed AST. Verilog/Zig keep their own pipelines. Effect on the test suite (was 1491 passed / 3 failed at HEAD): - test_let_binding_emitted_rust_1401 now PASSES (was failing) - test_let_binding_emitted_c_1401 now PASSES (was failing) - new test_two_reassigned_locals_survive_1455 PASSES - 1494 passed / 1 failed; the remaining failure (let_binding_is_lowered_1401, Verilog HIR path, does not call optimize) is pre-existing and untouched here. Downstream (gHashTag/tri-net): regenerating gen/rust with this t27c drops the E0425 wave from 2609 to 0; residual errors there are separate codegen bugs (bare `Vec<>` without a generic arg, a few type mismatches) tracked separately. FROZEN_HASH re-sealed (M5) for the compiler.rs change. phi^2 + phi^-2 = 3
1 parent 4832ec6 commit 4a4af13

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

bootstrap/src/compiler.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6183,8 +6183,10 @@ impl Compiler {
61836183
pub fn compile_c(source: &str) -> Result<String, String> {
61846184
let lexer = Lexer::new(source);
61856185
let mut parser = Parser::new(lexer);
6186-
let mut ast = parser.parse()?;
6187-
optimize(&mut ast, &OptConfig::default());
6186+
let ast = parser.parse()?;
6187+
// Emit FAITHFUL C from the AST; the C compiler optimizes downstream. See
6188+
// the note on compile_rust: t27c's optimizer drops reassigned locals and
6189+
// const-inlines `let`, corrupting the source-level output. Fixes #1455.
61886190
let mut codegen = CCodegen::new();
61896191
codegen.gen_c(&ast);
61906192
Ok(codegen.into_string())
@@ -6193,8 +6195,15 @@ impl Compiler {
61936195
pub fn compile_rust(source: &str) -> Result<String, String> {
61946196
let lexer = Lexer::new(source);
61956197
let mut parser = Parser::new(lexer);
6196-
let mut ast = parser.parse()?;
6197-
optimize(&mut ast, &OptConfig::default());
6198+
let ast = parser.parse()?;
6199+
// Emit FAITHFUL Rust from the AST. Do NOT run t27c's own optimizer on the
6200+
// Rust backend: several of its passes (const-propagation and the
6201+
// unconditional copy-propagation / dead-store passes) corrupt a
6202+
// reassigned mutable local -- e.g. `var x = 0; ... x = a;` loses its
6203+
// declaration while its uses remain, producing E0425. rustc/LLVM optimize
6204+
// the emitted code far more reliably, so faithful codegen is both correct
6205+
// and sufficient here. Verilog/Zig/C backends keep their own pipelines.
6206+
// Fixes gHashTag/t27#1455.
61986207
let mut codegen = RustCodegen::new();
61996208
codegen.gen_rust(&ast);
62006209
Ok(codegen.into_string())
@@ -22530,6 +22539,21 @@ mod tests_phase40_coverage {
2253022539
);
2253122540
}
2253222541

22542+
// #1455 regression: two consecutive reassigned locals must BOTH survive.
22543+
// The optimizer used to drop the first declaration (and const-inline `let`),
22544+
// leaving `x` undeclared while its uses remained (E0425). Faithful codegen
22545+
// on the Rust backend emits both `let mut` bindings.
22546+
#[test]
22547+
fn test_two_reassigned_locals_survive_1455() {
22548+
let code = "module M { pub fn f(a: u32) -> u32 { var x = 0; var y = 1; if (a > x) { x = a; y = 2; } return y; } }";
22549+
let out = Compiler::compile_rust(code).expect("compile should succeed");
22550+
assert!(
22551+
out.contains("let mut x = 0") && out.contains("let mut y = 1"),
22552+
"a reassigned local was dropped from Rust output: {}",
22553+
out
22554+
);
22555+
}
22556+
2253322557
// #1401 regression (C emitter shares the same lexer/parser root cause):
2253422558
// the `let` local must appear as a typed C declaration.
2253522559
#[test]

bootstrap/stage0/FROZEN_HASH

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
197d6eb5a40bed62ae806cb09c14fbde4d2664ed7cc6991c1e3bfa60983706ff bootstrap/src/compiler.rs
1+
6eb632b838e907f160934965972f408839d8bb2916e0447c0c1bade5bda98b18 bootstrap/src/compiler.rs

0 commit comments

Comments
 (0)