Bug 20719 – Self referential struct definition causes stack overflow

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Mac OS X
Creation time
2020-04-03T19:28:22Z
Last change time
2020-05-04T15:34:04Z
Keywords
pull
Assigned to
No Owner
Creator
Ben

Comments

Comment #0 by ben.james.jones — 2020-04-03T19:28:22Z
Trigger: import sumtype; struct A{} struct B { SumType!(This, A)[] elems; } relevant piece of the dmd stacktrace. isTypeIsolated calls itself recursively until the stack overflows. frame #130408: 0x0000000100152626 dmd`_D3dmd4func15FuncDeclaration14isTypeIsolatedMFCQBt5mtype4TypeZb + 254 frame #130409: 0x000000010004e13d dmd`implicitConvTo::ImplicitConvTo::visit(CallExp*) + 149 frame #130410: 0x000000010011960a dmd`CallExp::accept(Visitor*) + 34 frame #130411: 0x000000010004ccaa dmd`_D3dmd5dcast14implicitConvToFCQBc10expression10ExpressionCQCe5mtype4TypeZEQCu7globals5MATCH + 74 frame #130412: 0x000000010021be40 dmd`_D3dmd5mtype12TypeFunction9callMatchMFCQBlQBk4TypeACQBy10expression10ExpressioniPPxaPSQDg6dscope5ScopeZEQDy7globals5MATCH + 1744
Comment #1 by ben.james.jones — 2020-04-14T19:41:27Z
Reduced test case: import std.meta : AliasSeq; import std.typecons : ReplaceTypeUnless; import std.traits : isCopyable, isAssignable; struct This; //defined in std.variant this way struct SumType(TypeArgs) { alias Types = AliasSeq!(ReplaceTypeUnless!(isSumType, This, typeof(this), TypeArgs)); union Storage { template memberName(T) { mixin("enum memberName = `values_", "`;"); } static foreach (T; Types) mixin("T ", memberName!T, ";"); } Storage storage; static foreach (T; Types) static if (isCopyable!T){} static foreach (T; Types) static if (isAssignable!T){} } enum isSumType(T) = is(Args); struct B { SumType!(This)elems; }
Comment #2 by moonlightsentinel — 2020-04-15T02:16:36Z
Maybe related reduction from dustmite: ============================== alias AliasSeq(TList...) = TList; enum isCopyable(S) = { S foo; }; struct SumType { alias Types = AliasSeq!(typeof(this)); Types[0] t; alias cp = isCopyable!(Types[0]); } ================================ This also segfaults but prints test.d(6): Error: struct test.SumType cannot have field t with same struct type
Comment #3 by ben.james.jones — 2020-04-15T02:45:41Z
Not sure it's the same bug since mine triggers a stack overflow with no diagnostics. Here's the dustmite script I used to reduce: #!/bin/sh # arguments to dmd DMDARGS="test20719.d" OUTPUT=$(lldb --batch -o "run $DMDARGS" -k 'bt 30' -k 'quit' -o 'quit' dmd 2>&1) #echo $OUTPUT echo "$OUTPUT" | egrep -q "_D3dmd4func15FuncDeclaration14isTypeIsolatedMFCQBt5mtype4TypeZb" exit $?
Comment #4 by moonlightsentinel — 2020-04-15T03:05:45Z
Without error message: ================================ struct SumType { alias Types = AliasSeq!(typeof(this)); union Storage { Types[0] t; } Storage storage; static if (isCopyable!(Types[0])) {} static if (isAssignable!(Types[0])) {} } alias AliasSeq(TList...) = TList; enum isAssignable(Rhs) = __traits(compiles, lvalueOf = rvalueOf!Rhs); struct __InoutWorkaroundStruct {} T rvalueOf(T)(); T lvalueOf()(__InoutWorkaroundStruct); enum isCopyable(S) = { S foo; }; ===================================== Both original and reduction cause a segfault for me.
Comment #5 by dlang-bot — 2020-04-30T17:59:32Z
@benjones created dlang/dmd pull request #11083 "fix issue 20719 by passing previously seen structs to isTypeIsolated …" fixing this issue: - fix issue 20719 by passing previously seen structs to isTypeIsolated recursive calls https://github.com/dlang/dmd/pull/11083
Comment #6 by dlang-bot — 2020-05-04T15:34:04Z
dlang/dmd pull request #11083 "fix issue 20719 by passing previously seen structs to isTypeIsolated …" was merged into master: - 9fa18aa20a9975b2c5673522a4761a564c8b067b by Ben Jones: fix issue 20719 by passing previously seen structs to isTypeIsolated recursive calls https://github.com/dlang/dmd/pull/11083