Skip to content

fix(codegen): declare a hidden-visibility global across codegen units - #11817

Merged
proggeramlug merged 2 commits into
mainfrom
fix/codegen-external-decl-visibility
Oct 3, 2026
Merged

proggeramlug merged 2 commits into
mainfrom
fix/codegen-external-decl-visibility

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Symptom

Compiling OpenCode v1.18.30 on Linux x86_64 with main aborts in codegen (exit 134):

thread 'perry-module-1' panicked at crates/perry-codegen/src/module.rs:1083:25:
cannot form external declaration for generated global:
@perry_closure_opencode_node_modules__bun_effect_4_0_0_beta_83_node_modules_effect_src_Schema_ts__247$info
  = hidden constant { ptr, i16, i16, i32, i32, i32, ptr, i64, ptr, i32, i16, i16, i64 } { ... }

Cause

When a module is split into codegen units, a global defined in one unit and referenced from another needs an external declaration in the referencing unit. external_decl_for_global builds it, but it only stripped linkage keywords (private, internal, linkonce_odr, …) before expecting constant or global. Closure-info records are emitted as @…$info = hidden constant {…} (fn_info.rs, whose own tests assert that form) — hidden is a visibility keyword, so nothing matched, the function returned None, and module.rs:1083 panicked.

It is Linux/COFF-specific: on ELF and COFF generated globals are not replicated, so every cross-unit reference goes through this function. Mach-O replicates globals instead (promote_global_for_units), which is why the same OpenCode build never hit this on macOS. It needs a module big enough to split and a cross-unit reference to a closure-info record — effect's Schema.ts is both.

Fix

Parse the optional preemption (dso_local / dso_preemptable) and visibility (default / hidden / protected) keywords in LLVM's order after the linkage, and keep them on the declaration, so hidden constant {…} declares as external hidden constant {…}. The existing thread-local handling (#10399) is unchanged and composes with it; unnamed_addr / local_unnamed_addr describe only the definition and are dropped as before. Anything still unrecognised keeps returning None, so a genuinely unexpected form stays loud.

A scan of every @global = … prefix the codegen emits shows they are all declarable after this change: linkage forms are stripped, external … returns early, TLS and unnamed_addr were already handled, and hidden constant is the only visibility form emitted. Nothing emits addrspace or DLL storage on a global.

Test

module::tests::external_decl_keeps_hidden_visibility_of_closure_info covers the closure-info shape, dso_local hidden global, and hidden thread_local global.

  • Without the fix it fails with the production symptom: left: None, right: Some("@perry_closure_m__247$info = external hidden constant { ptr, i16, i16 }").
  • With the fix, all 26 perry-codegen module:: tests pass (--test-threads=1), including the existing external_decl_keeps_thread_local.

cargo fmt --all -- --check is clean on this head. The changelog fragment follows in a second commit once this PR has a number.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed a compiler failure on Linux/COFF when building projects that use cross-unit closure information. Hidden symbols are now handled without triggering a panic, while retaining their visibility and preemption behavior.

Ralph Küpper added 2 commits October 3, 2026 16:18
external_decl_for_global stripped only linkage keywords, so a definition
carrying a visibility keyword returned None. Closure-info records are emitted
`hidden constant` (fn_info.rs), and on ELF/COFF, where generated globals are
not replicated, every cross-unit reference to one is declared through this
function. Splitting a module as large as effect's Schema.ts into codegen units
then panicked with "cannot form external declaration for generated global".

Parse the preemption and visibility keywords in LLVM's order and keep them on
the declaration, so `hidden constant` becomes `external hidden constant`.
@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 01f87c9e-f9c8-4547-adc7-292f5d1b22d0
📥 Commits

Reviewing files that changed from the base of the PR and between f9a65b4 and 64910e0.

📒 Files selected for processing (3)
  • changelog.d/11817-codegen-hidden-visibility-decl.md
  • crates/perry-codegen/src/module/linkage.rs
  • crates/perry-codegen/src/module/tests.rs
 ______________________________
< torvalds@linux:~$ git review >
 ------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug
proggeramlug merged commit 1238de3 into main Oct 3, 2026
31 of 37 checks passed
@proggeramlug
proggeramlug deleted the fix/codegen-external-decl-visibility branch October 3, 2026 14:29
@proggeramlug

Copy link
Copy Markdown
Contributor Author

The four red jobs are pre-existing on main and outside this diff, which touches only perry-codegen/src/module/{linkage,tests}.rs plus the fragment:

job failure file
self-test-checkers thread-local policy: 2 raw thread_local! declarations perry-runtime/src/object/field_get_set/class_object_template.rs — on main at lines 86/105/455, from 9b9ba6bf07; #11781 fails the same job
lint heap-tag-only finding, "self-test FAILED: the tree is already red" perry-runtime/src/json/parse_api.rs:749
warnings -D warnings perry-stdlib/src/zlib.rs:1879 / :1881
cargo-test codegen_env_vars_are_build_cache_inputs (1222 passed, 1 failed) perry/src/commands/compile/build_cache.rs

The test this PR adds, and the rest of perry-codegen's module:: tests, are not among the failures.

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