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:
Martin Kinkelin 2020-05-29 18:28:45 +02:00 committed by GitHub
commit 75f18b49ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 44 deletions

View file

@ -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[]
*/ */

View file

@ -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;
} }

View file

@ -815,22 +815,24 @@ void defineParameters(IrFuncTy &irFty, VarDeclarations &parameters) {
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.

View file

@ -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);

View 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);
}