mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 15:40:55 +03:00
Merge pull request #3441 from kinke/fix_captured_nonpassed
Fix ICE for *captured* parameters *not* passed on the LLVM level
This commit is contained in:
commit
75f18b49ba
5 changed files with 64 additions and 44 deletions
|
@ -411,29 +411,6 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version (IN_LLVM)
|
|
||||||
{
|
|
||||||
// Make sure semantic analysis has been run on argument types. This is
|
|
||||||
// e.g. needed for TypeTuple!(int, int) to be picked up as two int
|
|
||||||
// parameters by the Parameter functions.
|
|
||||||
for (size_t i = 0; i < f.parameterList.length; i++)
|
|
||||||
{
|
|
||||||
Parameter arg = f.parameterList[i];
|
|
||||||
Type nw = arg.type.typeSemantic(Loc.initial, sc);
|
|
||||||
if (arg.type != nw)
|
|
||||||
{
|
|
||||||
arg.type = nw;
|
|
||||||
// Examine this index again.
|
|
||||||
// This is important if it turned into a tuple.
|
|
||||||
// In particular, the empty tuple should be handled or the
|
|
||||||
// next parameter will be skipped.
|
|
||||||
// LDC_FIXME: Maybe we only need to do this for tuples,
|
|
||||||
// and can add tuple.length after decrement?
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Declare all the function parameters as variables
|
/* Declare all the function parameters as variables
|
||||||
* and install them in parameters[]
|
* and install them in parameters[]
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -83,10 +83,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove 0-sized args (static arrays with 0 elements) and, for Darwin,
|
// remove 0-sized args (static arrays with 0 elements) and, for Darwin,
|
||||||
// empty structs too
|
// empty POD structs too
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < fty.args.size()) {
|
while (i < fty.args.size()) {
|
||||||
auto tb = fty.args[i]->type->toBasetype();
|
auto arg = fty.args[i];
|
||||||
|
if (!arg->byref) {
|
||||||
|
auto tb = arg->type->toBasetype();
|
||||||
|
|
||||||
if (tb->size() == 0) {
|
if (tb->size() == 0) {
|
||||||
fty.args.erase(fty.args.begin() + i);
|
fty.args.erase(fty.args.begin() + i);
|
||||||
|
@ -96,12 +98,13 @@ public:
|
||||||
// https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html#//apple_ref/doc/uid/TP40013702-SW1
|
// https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html#//apple_ref/doc/uid/TP40013702-SW1
|
||||||
if (isDarwin) {
|
if (isDarwin) {
|
||||||
if (auto ts = tb->isTypeStruct()) {
|
if (auto ts = tb->isTypeStruct()) {
|
||||||
if (ts->sym->fields.empty()) {
|
if (ts->sym->fields.empty() && ts->sym->isPOD()) {
|
||||||
fty.args.erase(fty.args.begin() + i);
|
fty.args.erase(fty.args.begin() + i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -815,22 +815,24 @@ void defineParameters(IrFuncTy &irFty, VarDeclarations ¶meters) {
|
||||||
size_t llArgIdx = 0;
|
size_t llArgIdx = 0;
|
||||||
|
|
||||||
for (VarDeclaration *vd : parameters) {
|
for (VarDeclaration *vd : parameters) {
|
||||||
|
Type *paramType = vd->type;
|
||||||
IrParameter *irparam = getIrParameter(vd);
|
IrParameter *irparam = getIrParameter(vd);
|
||||||
|
|
||||||
// vd->type (parameter) and irparam->arg->type (argument) don't always
|
|
||||||
// match.
|
|
||||||
// E.g., for a lazy parameter of type T, vd->type is T (with lazy storage
|
|
||||||
// class) while irparam->arg->type is the delegate type.
|
|
||||||
Type *const paramType = (irparam ? irparam->arg->type : vd->type);
|
|
||||||
|
|
||||||
if (!irparam) {
|
if (!irparam) {
|
||||||
// This is a parameter that is not passed on the LLVM level.
|
// This is a parameter that is not passed on the LLVM level.
|
||||||
// Create the param here and set it to a "dummy" alloca that
|
// Create the param here and set it to a "dummy" alloca that
|
||||||
// we do not store to here.
|
// we do not store to here.
|
||||||
irparam = getIrParameter(vd, true);
|
irparam = getIrParameter(vd, true);
|
||||||
irparam->value = DtoAlloca(vd, vd->ident->toChars());
|
irparam->value = DtoAlloca(vd, vd->ident->toChars());
|
||||||
|
} else if (!irparam->value) {
|
||||||
|
// Captured parameter not passed on the LLVM level.
|
||||||
|
assert(irparam->nestedIndex >= 0);
|
||||||
|
irparam->value = DtoAlloca(vd, vd->ident->toChars());
|
||||||
} else {
|
} else {
|
||||||
assert(irparam->value);
|
// vd->type (parameter) and irparam->arg->type (argument) don't always
|
||||||
|
// match. E.g., for a lazy parameter of type T, vd->type is T (with lazy
|
||||||
|
// storage class) while irparam->arg->type is the delegate type.
|
||||||
|
paramType = irparam->arg->type;
|
||||||
|
|
||||||
if (irparam->arg->byref) {
|
if (irparam->arg->byref) {
|
||||||
// The argument is an appropriate lvalue passed by reference.
|
// The argument is an appropriate lvalue passed by reference.
|
||||||
|
|
|
@ -392,14 +392,17 @@ static void DtoCreateNestedContextType(FuncDeclaration *fd) {
|
||||||
builder.alignCurrentOffset(alignment);
|
builder.alignCurrentOffset(alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
IrLocal &irLocal = *getIrLocal(vd, true);
|
const bool isParam = vd->isParameter();
|
||||||
|
|
||||||
|
IrLocal &irLocal =
|
||||||
|
*(isParam ? getIrParameter(vd, true) : getIrLocal(vd, true));
|
||||||
irLocal.nestedIndex = builder.currentFieldIndex();
|
irLocal.nestedIndex = builder.currentFieldIndex();
|
||||||
irLocal.nestedDepth = depth;
|
irLocal.nestedDepth = depth;
|
||||||
|
|
||||||
LLType *t = nullptr;
|
LLType *t = nullptr;
|
||||||
if (vd->isRef() || vd->isOut()) {
|
if (vd->isRef() || vd->isOut()) {
|
||||||
t = DtoType(vd->type->pointerTo());
|
t = DtoType(vd->type->pointerTo());
|
||||||
} else if (vd->isParameter() && (vd->storage_class & STClazy)) {
|
} else if (isParam && (vd->storage_class & STClazy)) {
|
||||||
// the type is a delegate (LL struct)
|
// the type is a delegate (LL struct)
|
||||||
Type *dt = TypeFunction::create(nullptr, vd->type, VARARGnone, LINKd);
|
Type *dt = TypeFunction::create(nullptr, vd->type, VARARGnone, LINKd);
|
||||||
dt = createTypeDelegate(dt);
|
dt = createTypeDelegate(dt);
|
||||||
|
|
35
tests/compilable/captured_nonpassed_params.d
Normal file
35
tests/compilable/captured_nonpassed_params.d
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Some ABIs don't pass empty static arrays or empty PODs as arguments.
|
||||||
|
// This can get hairy, e.g., if such a parameter is captured.
|
||||||
|
|
||||||
|
// RUN: %ldc -c -g %s
|
||||||
|
|
||||||
|
struct EmptyPOD {}
|
||||||
|
|
||||||
|
EmptyPOD emptyPOD(EmptyPOD e)
|
||||||
|
{
|
||||||
|
EmptyPOD nested() { return e; }
|
||||||
|
nested();
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[0] emptySArray(int[0] a)
|
||||||
|
{
|
||||||
|
int[0] nested() { return a; }
|
||||||
|
nested();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuple()
|
||||||
|
{
|
||||||
|
auto test(T...)(T params)
|
||||||
|
{
|
||||||
|
auto nested() { return params[0]; }
|
||||||
|
nested();
|
||||||
|
return params[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
test(EmptyPOD());
|
||||||
|
|
||||||
|
int[0] a;
|
||||||
|
test(a);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue