daslang 0.6.4 at master 237df6024, Linux x86_64 (WSL2, kernel 6.6), gcc 11.4, Release.
When a struct holds another struct by value and that inner struct points back at the outer one, -aot emits the outer struct's definition before the inner one's. C++ needs a complete type for a by-value member, so the generated file does not compile. The interpreter runs the same program; the -jit and -aot tiers disagree with it only because the C++ never builds.
Reproduction
back_pointer.das:
options gen2
struct Outer {
next : Outer?
embedded : Inner
tag : int
}
struct Inner {
owner : Outer?
a : int
b : int
}
[export]
def main() {
var o = Outer(tag = 7, embedded = Inner(a = 1, b = 2))
o.embedded.owner = unsafe(addr(o))
print("{o.embedded.owner.tag} {o.embedded.a + o.embedded.b}\n")
}
$ daslang back_pointer.das
7 3
$ daslang -aot back_pointer.das back_pointer.das.cpp
$ g++ -std=c++17 -fsyntax-only -I include back_pointer.das.cpp
back_pointer.das.cpp:345:18: error: field 'embedded' has incomplete type 'das::_anon_...::Inner'
back_pointer.das.cpp:348:28: error: static assertion failed: structure size mismatch with DAS
back_pointer.das.cpp:351:34: error: static assertion failed: structure field offset mismatch with DAS
The generated file, in order:
struct Outer {
struct Outer * next;
struct Inner embedded; // Inner is not defined yet
int32_t tag;
};
...
struct Inner {
struct Outer * owner;
...
Declaring Inner before Outer in the source is a workaround; a pointer member (owner : Outer?) needs only a forward declaration, which the emitter already writes for every struct.
Expected
The emitter orders struct definitions by their by-value dependencies (a struct is defined after every struct it embeds), and treats pointer members as satisfied by the forward declaration. The program compiles under -aot as it runs in the interpreter.
Test
Drops into tests/language/ as test_struct_by_value_back_pointer.das: it passes interpreted, and the AOT lane (test_aot_subset compiles tests/language) fails to build the generated C++ on master.
options gen2
require dastest/testing_boost
struct Outer {
next : Outer?
embedded : Inner
tag : int
}
struct Inner {
owner : Outer?
a : int
b : int
}
[test]
def test_by_value_member_with_a_back_pointer(t : T?) {
var o = Outer(tag = 7, embedded = Inner(a = 1, b = 2))
o.embedded.owner = unsafe(addr(o))
t |> equal(o.embedded.owner.tag, 7)
t |> equal(o.embedded.a + o.embedded.b, 3)
}
daslang0.6.4 at master237df6024, Linux x86_64 (WSL2, kernel 6.6), gcc 11.4, Release.When a struct holds another struct by value and that inner struct points back at the outer one,
-aotemits the outer struct's definition before the inner one's. C++ needs a complete type for a by-value member, so the generated file does not compile. The interpreter runs the same program; the-jitand-aottiers disagree with it only because the C++ never builds.Reproduction
back_pointer.das:The generated file, in order:
Declaring
InnerbeforeOuterin the source is a workaround; a pointer member (owner : Outer?) needs only a forward declaration, which the emitter already writes for every struct.Expected
The emitter orders struct definitions by their by-value dependencies (a struct is defined after every struct it embeds), and treats pointer members as satisfied by the forward declaration. The program compiles under
-aotas it runs in the interpreter.Test
Drops into
tests/language/astest_struct_by_value_back_pointer.das: it passes interpreted, and the AOT lane (test_aot_subsetcompilestests/language) fails to build the generated C++ on master.