Skip to content

codegen: void main() should exit 0, not leak a garbage exit code#3

Merged
cs01 merged 1 commit into
mainfrom
fix-void-entrypoint-exit
May 31, 2026
Merged

codegen: void main() should exit 0, not leak a garbage exit code#3
cs01 merged 1 commit into
mainfrom
fix-void-entrypoint-exit

Conversation

@cs01

@cs01 cs01 commented May 31, 2026

Copy link
Copy Markdown
Owner

Bug

fn main() with no return type (a void main) was compiled to define void @main(...). But main is the process entry point — the OS reads its return register as the exit code. A void function leaves garbage in that register, so a program that should succeed exited nonzero (consistently 10 in testing), e.g.:

fn main() {
    print(42)   // prints 42, then exits 10
}

This is why fixtures had to end in a string print or use fn main(): i32 { ... return 0 } to pass — an int-ending void main failed the harness's exit-code check. Surfaced while adding the compound-bitwise fixture.

Fix

In genFn, force @main to be i32-returning regardless of the Milo signature, and make a bare return inside main emit ret i32 0 (so it matches the forced signature). The existing fallthrough already emits ret i32 0 once the return type is i32. Explicit return <n> exit codes are preserved.

Tests

  • tests/fixtures/voidMainExit.milo — void main ending in print(<int>), must exit 0.
  • Verified: fn main(): i32 { return 5 } still exits 5; full suite 349 pass / 0 fail.

@cs01 cs01 merged commit f6481f7 into main May 31, 2026
2 checks passed
@cs01 cs01 deleted the fix-void-entrypoint-exit branch May 31, 2026 21:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant