mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30:43 +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
|
||||
* and install them in parameters[]
|
||||
*/
|
||||
|
|
|
@ -83,10 +83,12 @@ public:
|
|||
}
|
||||
|
||||
// remove 0-sized args (static arrays with 0 elements) and, for Darwin,
|
||||
// empty structs too
|
||||
// empty POD structs too
|
||||
size_t i = 0;
|
||||
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) {
|
||||
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
|
||||
if (isDarwin) {
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -815,22 +815,24 @@ void defineParameters(IrFuncTy &irFty, VarDeclarations ¶meters) {
|
|||
size_t llArgIdx = 0;
|
||||
|
||||
for (VarDeclaration *vd : parameters) {
|
||||
Type *paramType = vd->type;
|
||||
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) {
|
||||
// This is a parameter that is not passed on the LLVM level.
|
||||
// Create the param here and set it to a "dummy" alloca that
|
||||
// we do not store to here.
|
||||
irparam = getIrParameter(vd, true);
|
||||
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 {
|
||||
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) {
|
||||
// The argument is an appropriate lvalue passed by reference.
|
||||
|
|
|
@ -392,14 +392,17 @@ static void DtoCreateNestedContextType(FuncDeclaration *fd) {
|
|||
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.nestedDepth = depth;
|
||||
|
||||
LLType *t = nullptr;
|
||||
if (vd->isRef() || vd->isOut()) {
|
||||
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)
|
||||
Type *dt = TypeFunction::create(nullptr, vd->type, VARARGnone, LINKd);
|
||||
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