Repository navigation
rc: a global takes the reference of an owned producer through a widening view (#459) - #468
Merged
Merged
Conversation
…ing view (#459) `let G: Node | null = mk()` at module level was freed at start under rc (and own). The initializer gives the call's result to `ts.GlobalResult` through a cast to the union; the cast is the call's one use, and a releasable one, so the call's reference was given back at the end of the region as a discarded temporary, and the global pointed at freed memory. A plain `let G = mk()` gives the call to the terminator straight and was fine. claimHandleGlobalInitializers did exactly this claim for Shared<T> handles (own spec 23.1); it is now claimGlobalInitializers and covers every global whose type owns a block: a producer that carries an owned reference, reached through ts.Cast, ts.OptionalValue or ts.CreateUnionInstance, is marked consumed, and the global keeps its count. The retain for a handle read out of a field or element stays handle-only, since under own a retain left in a global's region is an error for any other type. Test: 00global_union_from_call (compile and JIT, and in the rc/none corpus): `Node | null` let and const globals and a `Node | undefined` global from calls, read after allocations of the same size have reused anything freed, then reassigned. It failed under rc before the change. The own corpus is unchanged (453 / 593, 451 with --opt). Fixes #459. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…izers # Conflicts: # tslang/test/tester/CMakeLists.txt
This was referenced Oct 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #459.
Under rc and own, a module-level
let G: Node | null = mk()was freed at start. The initializer passes the call's result tots.GlobalResultthrough a cast to the union. That cast is the call's only use, and a releasable one, so the call's reference was given back at the end of the region as a discarded temporary. The global then pointed at freed memory. A plainlet G = mk()passes the call to the terminator directly, so it was fine.claimHandleGlobalInitializersalready made exactly this claim forShared<T>handles (own spec 23.1). It is renamedclaimGlobalInitializersand now covers every global whose type owns a block. When a producer carrying an owned reference is reached throughts.Cast,ts.OptionalValueorts.CreateUnionInstance, it is marked consumed, and the global keeps its count.The retain for a handle read out of a field or element stays handle-only, because under own a retain left in a global's region is an error for any other type.
Tests
00global_union_from_call.ts:Node | nullletandconstglobals and aNode | undefinedglobal, each initialised from a call, read after allocations of the same size have reused anything freed, then reassigned.made1under rc and own; before, it printedk1andk26.--opt, same files.test-compile-gc-defaultlib-collector, the known local LNK2005 against the stale installed default library, which fails the same way on main.Not covered here: #461, a global object literal
{ s: mk() }. There the call's result is stored into a field of the literal's temporary rather than reaching the global through a view, so it needs its own fix.🤖 Generated with Claude Code