Fixed two issues with nested functions as template alias parameters.

Fixes #131 (GitHub).
This commit is contained in:
David Nadlinger 2012-10-07 02:40:10 +02:00
parent da17b7c6b6
commit 051cd7302e
3 changed files with 43 additions and 10 deletions

View file

@ -193,6 +193,14 @@ void DtoResolveNestedContext(Loc loc, ClassDeclaration *decl, LLValue *value)
// store into right location // store into right location
if (!llvm::dyn_cast<llvm::UndefValue>(nest)) { if (!llvm::dyn_cast<llvm::UndefValue>(nest)) {
// Need to make sure the declaration has already been resolved, because
// when multiple source files are specified on the command line, the
// frontend sometimes adds "nested" (i.e. a template in module B
// instantiated from module A with a type from module A instantiates
// another template from module B) into the wrong module, messing up
// our codegen order.
DtoResolveDsymbol(decl);
size_t idx = decl->vthis->ir.irField->index; size_t idx = decl->vthis->ir.irField->index;
LLValue* gep = DtoGEPi(value,0,idx,".vthis"); LLValue* gep = DtoGEPi(value,0,idx,".vthis");
DtoStore(DtoBitCast(nest, gep->getType()->getContainedType(0)), gep); DtoStore(DtoBitCast(nest, gep->getType()->getContainedType(0)), gep);

View file

@ -324,18 +324,28 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
assert(0 && "not global/function"); assert(0 && "not global/function");
} }
// The following breaks for nested naked functions and the implicitly // If the function needs to be defined in the current module, check if it
// generated __require/__ensure functions for in/out contracts. The reason // is a nested function and we can declare it as internal.
bool canInternalize = mustDefine;
// Nested naked functions and the implicitly generated __require/__ensure
// functions for in/out contracts cannot be internalized. The reason
// for the latter is that contract functions, despite being nested, can be // for the latter is that contract functions, despite being nested, can be
// referenced from other D modules e.g. in the case of contracts on // referenced from other D modules e.g. in the case of contracts on
// interface methods (where __require/__ensure are emitted to the module // interface methods (where __require/__ensure are emitted to the module
// where the interface is declared, but an actual interface implementation // where the interface is declared, but an actual interface implementation
// can be in a completely different place). // can be in a completely different place).
bool skipNestedCheck = !mustDefine; if (canInternalize)
if (!skipNestedCheck) {
if (FuncDeclaration* fd = sym->isFuncDeclaration()) if (FuncDeclaration* fd = sym->isFuncDeclaration())
skipNestedCheck = (fd->naked != 0) || {
(fd->ident == Id::require) || (fd->ident == Id::ensure); if ((fd->naked != 0) ||
(fd->ident == Id::require) || (fd->ident == Id::ensure))
{
canInternalize = false;
}
}
}
// Any symbol nested in a function that cannot be inlined can't be // Any symbol nested in a function that cannot be inlined can't be
// referenced directly from outside that function, so we can give // referenced directly from outside that function, so we can give
@ -350,11 +360,26 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
// --- // ---
// if instances get emitted in multiple object files because they'd use // if instances get emitted in multiple object files because they'd use
// different instances of 'i'. // different instances of 'i'.
if (!skipNestedCheck) { // TODO: Check if we are giving away too much inlining potential due to
for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent) { // canInline being overly conservative here.
if (canInternalize)
{
for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent)
{
FuncDeclaration *fd = parent->isFuncDeclaration(); FuncDeclaration *fd = parent->isFuncDeclaration();
if (fd && !fd->canInline(fd->needThis())) if (fd && !fd->canInline(fd->needThis()))
return llvm::GlobalValue::InternalLinkage; {
// We also cannot internalize nested functions which are
// leaked to the outside via a templated return type, because
// that type will also be codegen'd in any caller modules (see
// GitHub issue #131).
// Since we can't easily determine if this is really the case
// here, just don't internalize it if the parent returns a
// template at all, to be safe.
TypeFunction* tf = static_cast<TypeFunction*>(fd->type);
if (!DtoIsTemplateInstance(tf->next->toDsymbol(fd->scope)))
return llvm::GlobalValue::InternalLinkage;
}
} }
} }

@ -1 +1 @@
Subproject commit 3c31326cd252d5401aedf8ff2893145622df4c98 Subproject commit a4a9f2860569e99dd69dea6b6ab5f5faf11cb920