From bebc5cce288a1082e0e287642c13e72f3619b1d6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 7 Sep 2012 03:12:33 +0200 Subject: [PATCH] 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. --- gen/llvmhelpers.cpp | 14 +------------- gen/tocall.cpp | 34 +++++++++++++++++++++++++++++++++- gen/toir.cpp | 18 ++++++++++++++++-- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 910e785d..f8b8ae40 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -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(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 diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 0a83c0ec..5b6b4696 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -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'; diff --git a/gen/toir.cpp b/gen/toir.cpp index c348dd10..d5503094 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -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(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())