Summary
When a nested function accesses a struct field only through __traits(getMember, this, "field"), the compiler does not register a nested reference to the enclosing member this. As a result, vthis is omitted from the closure frame, and the delegate segfaults at runtime.
A direct field access (this.field) in the same position works correctly because expressionSemantic on a DotVarExp with ThisExp calls checkNestedReference. But getMember with wantsym returns the member VarDeclaration without keeping a ThisExp use, so the nested capture is never recorded.
Reproducer
struct Struct
{
int field = 42;
auto nestedThunk()
{
int inner()
{
return __traits(getMember, this, "field");
}
return &inner;
}
}
void main()
{
auto s = Struct();
auto dg = s.nestedThunk();
assert(dg() == 42); // segfault: vthis missing from closure frame
}
Replacing __traits(getMember, this, "field") with this.field makes it work.
Expected behaviour
The delegate returned by nestedThunk should capture this and return 42.
Where
compiler/src/dmd/traits.d, inside the getMember branch of semanticTraits: after expressionSemantic on the resolved member, when the lookup object is this, checkNestedReference should be called on te.var (the enclosing member this).
Also affects LDC (ldc-developers/ldc#5203) since it shares the same frontend code.
Summary
When a nested function accesses a struct field only through
__traits(getMember, this, "field"), the compiler does not register a nested reference to the enclosing memberthis. As a result,vthisis omitted from the closure frame, and the delegate segfaults at runtime.A direct field access (
this.field) in the same position works correctly becauseexpressionSemanticon aDotVarExpwithThisExpcallscheckNestedReference. ButgetMemberwithwantsymreturns the memberVarDeclarationwithout keeping aThisExpuse, so the nested capture is never recorded.Reproducer
Replacing
__traits(getMember, this, "field")withthis.fieldmakes it work.Expected behaviour
The delegate returned by
nestedThunkshould capturethisand return42.Where
compiler/src/dmd/traits.d, inside thegetMemberbranch ofsemanticTraits: afterexpressionSemanticon the resolved member, when the lookup object isthis,checkNestedReferenceshould be called onte.var(the enclosing memberthis).Also affects LDC (ldc-developers/ldc#5203) since it shares the same frontend code.