Workaround for Voldemort return type handling issues.

See the comment in DtoCallFunction for an explanation of what is
going on.

The struct zero initialization code was also refactored out to
AssignExp::toElem and modified so that it is only triggered
on integer->struct assignments, not for any types where the
modifier-stripped types don't match up. This would have lead to
silently wrong code in the cases where the assert would have been
triggered otherwise.

Fixes the Phobos testsuite build.
This commit is contained in:
David Nadlinger
2012-09-07 03:12:33 +02:00
parent 139e1a9c2a
commit bebc5cce28
3 changed files with 50 additions and 16 deletions

View File

@@ -393,19 +393,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op)
Type* t2 = rhs->getType()->toBasetype();
if (t->ty == Tstruct) {
if (!stripModifiers(t)->equals(stripModifiers(t2))) {
// FIXME: use 'rhs' for something !?!
DtoAggrZeroInit(lhs->getLVal());
#if DMDV2
TypeStruct *ts = static_cast<TypeStruct*>(lhs->getType());
if (ts->sym->isNested() && ts->sym->vthis)
DtoResolveNestedContext(loc, ts->sym, lhs->getLVal());
#endif
}
else {
DtoAggrCopy(lhs->getLVal(), rhs->getRVal());
}
DtoAggrCopy(lhs->getLVal(), rhs->getRVal());
}
else if (t->ty == Tarray) {
// lhs is slice

View File

@@ -652,7 +652,39 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
break;
default:
assert(0 && "unhandled repainting of return value");
// Unfortunately, DMD has quirks resp. bugs with regard to name
// mangling: For voldemort-type functions which return a nested
// struct, the mangled name of the return type changes during
// semantic analysis.
//
// (When the function deco is first computed as part of
// determining the return type deco, its return type part is
// left off to avoid cycles. If mangle/toDecoBuffer is then
// called again for the type, it will pick up the previous
// result and return the full deco string for the nested struct
// type, consisting of both the full mangled function name, and
// the struct identifier.)
//
// Thus, the type merging in stripModifiers does not work
// reliably, and the equality check above can fail even if the
// types only differ in a qualifier.
//
// Because a proper fix for this in the frontend is hard, we
// just carry on and hope that the frontend didn't mess up,
// i.e. that the LLVM types really match up.
//
// An example situation where this case occurs is:
// ---
// auto iota() {
// static struct Result {
// this(int) {}
// inout(Result) test() inout { return cast(inout)Result(0); }
// }
// return Result.init;
// }
// void main() { auto r = iota(); }
// ---
break;
}
if (Logger::enabled())
Logger::cout() << "final return value: " << *retllval << '\n';

View File

@@ -607,10 +607,24 @@ DValue* AssignExp::toElem(IRState* p)
}
}
Logger::println("performing normal assignment");
DValue* l = e1->toElem(p);
DValue* r = e2->toElem(p);
if (e1->type->toBasetype()->ty == Tstruct && e2->op == TOKint64)
{
Logger::println("performing aggregate zero initialization");
assert(e2->toInteger() == 0);
DtoAggrZeroInit(l->getLVal());
#if DMDV2
TypeStruct *ts = static_cast<TypeStruct*>(e1->type);
if (ts->sym->isNested() && ts->sym->vthis)
DtoResolveNestedContext(loc, ts->sym, l->getLVal());
#endif
// Return value should be irrelevant.
return r;
}
Logger::println("performing normal assignment");
DtoAssign(loc, l, r, op);
if (l->isSlice())