/////////////////// test.cpp /////////////////////
template<class T>
struct List
{
T* begin;
};
struct StructWithDestructor
{
~StructWithDestructor();
int i;
};
StructWithDestructor::~StructWithDestructor()
{
}
StructWithDestructor getStructWithDestructor()
{
StructWithDestructor r;
r.i = 12345;
return r;
}
//////////////////// test.d //////////////////////
extern(C++) struct List(T)
{
// Any of the following static ifs can trigger the problem.
static if (T.sizeof > 4) {}
static if (__traits(isZeroInit, T)) {}
static if (__traits(isPOD, T)) {}
T* begin;
}
extern(C++) struct StructWithDestructor
{
~this();
alias L = List!StructWithDestructor;
int i;
}
extern(C++) StructWithDestructor getStructWithDestructor();
void main()
{
StructWithDestructor structWithDestructor = getStructWithDestructor();
assert(structWithDestructor.i == 12345);
}
//////////////////////////////////////////////////
The C++ function returns a struct, which is used by the D code. Currently the program crashes in getStructWithDestructor. The problem seems to be, that C++ tries to return the struct on the stack, but D expects it in a register.
This is caused by StructDeclaration.isPOD in the compiler returning true. It uses a cache, so it is only evaluated once, but calculates the wrong value on the first call, because the semantic run has not been completed for the struct at that time. A later call to isPOD could calculate the correct value, but the cache returns the wrong value. This is the same root cause as in https://issues.dlang.org/show_bug.cgi?id=20339.
It could be fixed by changing isPOD, so it does not rely on values calculated in the semantic run.
Comment #1 by dlang-bot — 2023-12-21T12:11:41Z
@tim-dlang updated dlang/dmd pull request #15939 "Calculate isPOD without information from semantic run" fixing this issue:
- Fixes issues 20339, 24292: Calculate isPOD without information from semantic run
Issue 20339: isPOD returns true if sizeof is accessed inside struct declaration
Issue 24292: Struct with destructor wrongly returned in register
Function StructDeclaration.isPOD can be called before the semantic run
for the struct is finished. It then uses incomplete information about
destructors, postblits and copy constructors. The result of isPOD is
cached, so later calls will also return the wrong result.
This commit changes isPOD, so it uses variables, which are already
filled before the semantic run.
https://github.com/dlang/dmd/pull/15939
Comment #2 by dlang-bot — 2023-12-21T22:20:19Z
dlang/dmd pull request #15939 "Fixes issues 20339, 24292: Calculate isPOD without information from semantic run" was merged into master:
- 3364291b569ea832091f576d354c6e4d598315ab by Tim Schendekehl:
Fixes issues 20339, 24292: Calculate isPOD without information from semantic run
Issue 20339: isPOD returns true if sizeof is accessed inside struct declaration
Issue 24292: Struct with destructor wrongly returned in register
Function StructDeclaration.isPOD can be called before the semantic run
for the struct is finished. It then uses incomplete information about
destructors, postblits and copy constructors. The result of isPOD is
cached, so later calls will also return the wrong result.
This commit changes isPOD, so it uses variables, which are already
filled before the semantic run.
https://github.com/dlang/dmd/pull/15939