Repository navigation
Compiler: a delegate thunk's call skips its sret arg when adding attributes - #2586
Merged
bfiete merged 2 commits intoOct 28, 2026
Merged
Conversation
…ibutes
A delegate's invoke thunk builds its own argument list for both the bound
and the static call, the sret pointer included, and hands CreateCall a
NULL sret. CreateCall's attribute pass only steps over the sret slot when
sret is non-NULL, so every parameter attribute after it was put on the
argument before its own. With a lowered struct ahead of a ref parameter,
the ref's dereferenceable landed on the struct's second i64:
struct Pos { public uint32 Line; public uint32 Column; }
struct Sel { public Pos A; public Pos B; }
static Pos Each(delegate Pos(Sel s, ref float goal) move) { ... }
LLVM rejected the module ("Attribute 'dereferenceable(4)' applied to
incompatible type!") and BeefBuild aborted. The pass now skips the
thunk's sret slot as well.
Seen in a game engine's code editor, whose per-selection edit and move
delegates take a selection by value beside a ref.
The thunk's call skipped its own sret slot when adding parameter attributes, but left it unmarked. On x86-64 that passes: sret goes in the first argument register either way. AArch64 passes sret in x8, apart from the arguments, and LLVM puts it there only for a parameter marked sret, so the callee read its return slot from the wrong register and Delegates.TestSretBeforeLoweredAndRef crashed (SIGSEGV in the lambda) on the arm64 CI runner. The slot is now marked as a real call's is.
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.
A delegate's invoke thunk builds its own argument list for both the bound
and the static call, the sret pointer included, and hands CreateCall a
NULL sret. CreateCall's attribute pass only steps over the sret slot when
sret is non-NULL, so every parameter attribute after it was put on the
argument before its own. With a lowered struct ahead of a ref parameter,
the ref's dereferenceable landed on the struct's second i64:
LLVM rejected the module ("Attribute 'dereferenceable(4)' applied to
incompatible type!") and BeefBuild aborted. The pass now skips the
thunk's sret slot as well.