char *mangle(Declaration *sthis) { OutBuffer buf; char *id; Dsymbol *s; //printf("::mangle(%s)\n", sthis->toChars()); s = sthis; do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); if (s->ident) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { id = mangle(fd); buf.prependstring(id); goto L1; } else { id = s->ident->toChars(); int len = strlen(id); char tmp[sizeof(len) * 3 + 1]; buf.prependstring(id); sprintf(tmp, "%d", len); buf.prependstring(tmp); } } else buf.prependstring("0"); s = s->parent; } while (s); // buf.prependstring("_D"); L1: //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); //printf("sthis->type = %s\n", sthis->type->toChars()); FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (sthis->type->deco) buf.writestring(sthis->type->deco); else { #ifdef DEBUG if (!fd->inferRetType) printf("%s\n", fd->toChars()); #endif assert(fd && fd->inferRetType); } id = buf.toChars(); buf.data = NULL; return id; }
LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) { // global/static variable if (VarDeclaration* vd = sym->isVarDeclaration()) { IF_LOG Logger::println("Variable %savailable externally: %s", (vd->availableExternally ? "" : "not "), vd->toChars()); // generated by inlining semantics run if (vd->availableExternally) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (DtoIsTemplateInstance(sym)) return templateLinkage; // Currently, we have to consider all variables, even function-local // statics, to be external, as CTFE might cause template functions // instances to be semantic3'd that occur within the body of a function // from an imported module. Consequently, a copy of them is codegen'd // in the importing module, even if they might reference a static in a // function in the imported module (e.g. via an alias parameter). // // A fix for this would be to track instantiations/semantic3 runs made // solely for CTFE purposes in a way similar to how the extra inlining // semantic runs are handled. // // LDC_FIXME: Can this also occur for functions? Find a better solution. if (true || vd->storage_class & STCextern) return llvm::GlobalValue::ExternalLinkage; } else if (FuncDeclaration* fdecl = sym->isFuncDeclaration()) { IF_LOG Logger::println("Function %savailable externally: %s", (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); assert(fdecl->type->ty == Tfunction); TypeFunction* ft = static_cast<TypeFunction*>(fdecl->type); // intrinsics are always external if (fdecl->llvmInternal == LLVMintrinsic) return llvm::GlobalValue::ExternalLinkage; // Mark functions generated by an inlining semantic run as // available_externally. Naked functions are turned into module-level // inline asm and are thus declaration-only as far as the LLVM IR level // is concerned. if (fdecl->availableExternally && !fdecl->naked) return llvm::GlobalValue::AvailableExternallyLinkage; // array operations are always template linkage if (fdecl->isArrayOp == 1) return templateLinkage; // template instances should have weak linkage // but only if there's a body, and it's not naked // otherwise we make it external if (DtoIsTemplateInstance(fdecl) && fdecl->fbody && !fdecl->naked) return templateLinkage; // extern(C) functions are always external if (ft->linkage == LINKc) return llvm::GlobalValue::ExternalLinkage; // If a function without a body is nested in another // function, we cannot use internal linkage for that // function (see below about nested functions) // FIXME: maybe there is a better way without emission // of needless symbols? if (!fdecl->fbody) return llvm::GlobalValue::ExternalLinkage; } // class else if (ClassDeclaration* cd = sym->isClassDeclaration()) { IF_LOG Logger::println("Class %savailable externally: %s", (cd->availableExternally ? "" : "not "), vd->toChars()); // generated by inlining semantics run if (cd->availableExternally) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (DtoIsTemplateInstance(cd)) return templateLinkage; } else { llvm_unreachable("not global/function"); } // The logic here should be sound in theory, but as long as the frontend // keeps inserting templates into wrong modules, this yields to linking // errors (see e.g. GitHub issue #558). #if 0 // Check if sym is a nested function and we can declare it as internal. // // 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 // referenced from other D modules e.g. in the case of contracts on // interface methods (where __require/__ensure are emitted to the module // where the interface is declared, but an actual interface implementation // can be in a completely different place). FuncDeclaration* fd = sym->isFuncDeclaration(); if (!fd || (!fd->naked && fd->ident != Id::require && fd->ident != Id::ensure)) { // Any symbol nested in a function that cannot be inlined can't be // referenced directly from outside that function, so we can give // such symbols internal linkage. This holds even if nested indirectly, // such as member functions of aggregates nested in functions. // // Note: This must be checked after things like template member-ness or // symbols nested in templates would get duplicated for each module, // breaking things like // --- // int counter(T)() { static int i; return i++; }" // --- // if instances get emitted in multiple object files because they'd use // different instances of 'i'. // TODO: Check if we are giving away too much inlining potential due to // canInline being overly conservative here. for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent) { FuncDeclaration *parentFd = parent->isFuncDeclaration(); if (parentFd && !parentFd->canInline(parentFd->needThis(), false, false)) { // 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*>(parentFd->type); if (!DtoIsTemplateInstance(tf->next->toDsymbol(parentFd->scope))) return llvm::GlobalValue::InternalLinkage; } } } #endif // default to external linkage return llvm::GlobalValue::ExternalLinkage; }
/****************************************************************************** * isv : for the enclosing auto functions of an inner class/struct type. * An aggregate type which defined inside auto function, it might * become Voldemort Type so its object might be returned. * This flag is necessary due to avoid mutual mangling * between return type and enclosing scope. See bugzilla 8847. */ char *mangleDecl(Declaration *sthis, bool isv) { OutBuffer buf; char *id; Dsymbol *s; //printf("::mangleDecl(%s)\n", sthis->toChars()); s = sthis; do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); if (s->getIdent()) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { id = mangleDecl(fd, isv); buf.prependstring(id); goto L1; } else { id = s->ident->toChars(); size_t len = strlen(id); char tmp[sizeof(len) * 3 + 1]; buf.prependstring(id); sprintf(tmp, "%d", (int)len); buf.prependstring(tmp); } } else buf.prependstring("0"); TemplateInstance *ti = s->isTemplateInstance(); if (ti && !ti->isTemplateMixin()) s = ti->tempdecl->parent; else s = s->parent; } while (s); // buf.prependstring("_D"); L1: //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); //printf("sthis->type = %s\n", sthis->type->toChars()); FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (isv && fd && (fd->inferRetType || getFuncTemplateDecl(fd))) { #if DDMD TypeFunction *tfn = (TypeFunction *)sthis->type->copy(); TypeFunction *tfo = (TypeFunction *)sthis->originalType; tfn->purity = tfo->purity; tfn->isnothrow = tfo->isnothrow; tfn->isproperty = tfo->isproperty; tfn->isref = fd->storage_class & STCauto ? false : tfo->isref; tfn->trust = tfo->trust; tfn->next = NULL; // do not mangle return type tfn->toDecoBuffer(&buf, 0); #else TypeFunction tfn = *(TypeFunction *)sthis->type; TypeFunction *tfo = (TypeFunction *)sthis->originalType; tfn.purity = tfo->purity; tfn.isnothrow = tfo->isnothrow; tfn.isproperty = tfo->isproperty; tfn.isref = fd->storage_class & STCauto ? false : tfo->isref; tfn.trust = tfo->trust; tfn.next = NULL; // do not mangle return type tfn.toDecoBuffer(&buf, 0); #endif } else if (sthis->type->deco) buf.writestring(sthis->type->deco); else { #ifdef DEBUG if (!fd->inferRetType) printf("%s\n", fd->toChars()); #endif assert(fd && fd->inferRetType && fd->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)sthis->type; Type *tn = tf->next; tf->next = NULL; // do not mangle undetermined return type tf->toDecoBuffer(&buf, 0); tf->next = tn; } id = buf.extractString(); return id; }
Expression *SymOffExp::castTo(Scope *sc, Type *t) { #if 0 printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif Expression *e = this; Type *tb = t->toBasetype(); Type *typeb = type->toBasetype(); if (tb != typeb) { // Look for pointers to functions where the functions are overloaded. FuncDeclaration *f; if (typeb->ty == Tpointer && typeb->next->ty == Tfunction && tb->ty == Tpointer && tb->next->ty == Tfunction) { f = var->isFuncDeclaration(); if (f) { f = f->overloadExactMatch(tb->next, m); if (f) { #if DMDV2 if (tb->ty == Tdelegate) { if (f->needThis() && hasThis(sc)) { e = new DelegateExp(loc, new ThisExp(loc), f); e = e->semantic(sc); } else if (f->isNested()) { e = new DelegateExp(loc, new IntegerExp(0), f); e = e->semantic(sc); } else if (f->needThis()) { error("no 'this' to create delegate for %s", f->toChars()); return new ErrorExp(); } else { error("cannot cast from function pointer to delegate"); return new ErrorExp(); } } else #endif { e = new SymOffExp(loc, f, 0); e->type = t; } #if DMDV2 f->tookAddressOf++; #endif return e; } } } e = Expression::castTo(sc, t); } else { e->type = t; } return e; }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame && ident != Id::identifier) { TemplateInstance::semanticTiargs(loc, sc, args, 1); } size_t dim = args ? args->dim : 0; Object *o; Declaration *d; FuncDeclaration *f; #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ { Type *t = getType((Object *)args->data[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ { Dsymbol *s = getDsymbol((Object *)args->data[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; if (ident == Id::isArithmetic) { ISTYPE(t->isintegral() || t->isfloating()) } else if (ident == Id::isFloating) { ISTYPE(t->isfloating()) } else if (ident == Id::isIntegral) { ISTYPE(t->isintegral()) } else if (ident == Id::isScalar) { ISTYPE(t->isscalar()) } else if (ident == Id::isUnsigned) { ISTYPE(t->isunsigned()) } else if (ident == Id::isAssociativeArray) { ISTYPE(t->toBasetype()->ty == Taarray) } else if (ident == Id::isStaticArray) { ISTYPE(t->toBasetype()->ty == Tsarray) } else if (ident == Id::isAbstractClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract()) } else if (ident == Id::isFinalClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) } else if (ident == Id::isAbstractFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) } else if (ident == Id::isVirtualFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual()) } else if (ident == Id::isFinalFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal()) } #if DMDV2 else if (ident == Id::isStaticFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && !f->needThis()) } else if (ident == Id::isRef) { ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isRef()) } else if (ident == Id::isOut) { ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isOut()) } else if (ident == Id::isLazy) { ISDSYMBOL((d = s->isDeclaration()) != NULL && d->storage_class & STClazy) } else if (ident == Id::identifier) { // Get identifier for symbol as a string literal // Specify 0 for the flags argument to semanticTiargs() so that // a symbol should not be folded to a constant. TemplateInstance::semanticTiargs(loc, sc, args, 0); if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[0]; Dsymbol *s = getDsymbol(o); if (!s || !s->ident) { error("argument %s has no identifier", o->toChars()); goto Lfalse; } StringExp *se = new StringExp(loc, s->ident->toChars()); return se->semantic(sc); } else if (ident == Id::parent) { if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[0]; Dsymbol *s = getDsymbol(o); if (s) s = s->toParent(); if (!s) { error("argument %s has no parent", o->toChars()); goto Lfalse; } return (new DsymbolExp(loc, s))->semantic(sc); } #endif else if (ident == Id::hasMember || ident == Id::getMember || ident == Id::getOverloads || ident == Id::getVirtualFunctions) { if (dim != 2) goto Ldimerror; Object *o = (Object *)args->data[0]; Expression *e = isExpression((Object *)args->data[1]); if (!e) { error("expression expected as second argument of __traits %s", ident->toChars()); goto Lfalse; } e = e->optimize(WANTvalue | WANTinterpret); if (e->op != TOKstring) { error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars()); goto Lfalse; } StringExp *se = (StringExp *)e; se = se->toUTF8(sc); if (se->sz != 1) { error("string must be chars"); goto Lfalse; } Identifier *id = Lexer::idPool((char *)se->string); Type *t = isType(o); e = isExpression(o); Dsymbol *s = isDsymbol(o); if (t) e = typeDotIdExp(loc, t, id); else if (e) e = new DotIdExp(loc, e, id); else if (s) { e = new DsymbolExp(loc, s); e = new DotIdExp(loc, e, id); } else { error("invalid first argument"); goto Lfalse; } if (ident == Id::hasMember) { /* Take any errors as meaning it wasn't found */ e = e->trySemantic(sc); if (!e) { if (global.gag) global.errors++; goto Lfalse; } else goto Ltrue; } else if (ident == Id::getMember) { e = e->semantic(sc); return e; } else if (ident == Id::getVirtualFunctions || ident == Id::getOverloads) { unsigned errors = global.errors; Expression *ex = e; e = e->semantic(sc); if (errors < global.errors) error("%s cannot be resolved", ex->toChars()); /* Create tuple of functions of e */ //e->dump(0); Expressions *exps = new Expressions(); FuncDeclaration *f; if (e->op == TOKvar) { VarExp *ve = (VarExp *)e; f = ve->var->isFuncDeclaration(); } else if (e->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)e; f = dve->var->isFuncDeclaration(); } else f = NULL; Ptrait p; p.exps = exps; p.e1 = e; p.ident = ident; overloadApply(f, fptraits, &p); TupleExp *tup = new TupleExp(loc, exps); return tup->semantic(sc); } else assert(0); } else if (ident == Id::classInstanceSize) { if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) { error("first argument is not a class"); goto Lfalse; } return new IntegerExp(loc, cd->structsize, Type::tsize_t); } else if (ident == Id::allMembers || ident == Id::derivedMembers) { if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sd; if (!s) { error("argument has no members"); goto Lfalse; } if ((sd = s->isScopeDsymbol()) == NULL) { error("%s %s has no members", s->kind(), s->toChars()); goto Lfalse; } Expressions *exps = new Expressions; while (1) { size_t dim = ScopeDsymbol::dim(sd->members); for (size_t i = 0; i < dim; i++) { Dsymbol *sm = ScopeDsymbol::getNth(sd->members, i); //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { //printf("\t%s\n", sm->ident->toChars()); char *str = sm->ident->toChars(); /* Skip if already present in exps[] */ for (size_t j = 0; j < exps->dim; j++) { StringExp *se2 = (StringExp *)exps->data[j]; if (strcmp(str, (char *)se2->string) == 0) goto Lnext; } StringExp *se = new StringExp(loc, str); exps->push(se); } Lnext: ; } ClassDeclaration *cd = sd->isClassDeclaration(); if (cd && cd->baseClass && ident == Id::allMembers) sd = cd->baseClass; // do again with base class else break; } #if DMDV1 Expression *e = new ArrayLiteralExp(loc, exps); #endif #if DMDV2 /* Making this a tuple is more flexible, as it can be statically unrolled. * To make an array literal, enclose __traits in [ ]: * [ __traits(allMembers, ...) ] */ Expression *e = new TupleExp(loc, exps); #endif e = e->semantic(sc); return e; } else if (ident == Id::compiles) { /* Determine if all the objects - types, expressions, or symbols - * compile without error */ if (!dim) goto Lfalse; for (size_t i = 0; i < dim; i++) { Object *o = (Object *)args->data[i]; Expression *e; unsigned errors = global.errors; global.gag++; Type *t = isType(o); if (t) { Dsymbol *s; t->resolve(loc, sc, &e, &t, &s); if (t) t->semantic(loc, sc); else if (e) { e = e->semantic(sc); e = e->optimize(WANTvalue); } } else { e = isExpression(o); if (e) { e = e->semantic(sc); e = e->optimize(WANTvalue); } } global.gag--; if (errors != global.errors) { global.errors = errors; goto Lfalse; } } goto Ltrue; } else if (ident == Id::isSame) { /* Determine if two symbols are the same */ if (dim != 2) goto Ldimerror; TemplateInstance::semanticTiargs(loc, sc, args, 0); Object *o1 = (Object *)args->data[0]; Object *o2 = (Object *)args->data[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); #if 0 printf("o1: %p\n", o1); printf("o2: %p\n", o2); if (!s1) { Expression *ea = isExpression(o1); if (ea) printf("%s\n", ea->toChars()); Type *ta = isType(o1); if (ta) printf("%s\n", ta->toChars()); goto Lfalse; } else printf("%s %s\n", s1->kind(), s1->toChars()); #endif if (!s1 && !s2) { Expression *ea1 = isExpression(o1); Expression *ea2 = isExpression(o2); if (ea1 && ea2) { if (ea1->equals(ea2)) goto Ltrue; } } if (!s1 || !s2) goto Lfalse; s1 = s1->toAlias(); s2 = s2->toAlias(); if (s1 == s2) goto Ltrue; else goto Lfalse; } else { error("unrecognized trait %s", ident->toChars()); goto Lfalse; } return NULL; Lnottype: error("%s is not a type", o->toChars()); goto Lfalse; Ldimerror: error("wrong number of arguments %d", dim); goto Lfalse; Lfalse: return new IntegerExp(loc, 0, Type::tbool); Ltrue: return new IntegerExp(loc, 1, Type::tbool); }
LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) { const bool mustDefine = mustDefineSymbol(sym); // global variable if (VarDeclaration* vd = sym->isVarDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Variable %savailable externally: %s", (vd->availableExternally ? "" : "not "), vd->toChars()); } // generated by inlining semantics run if (vd->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (needsTemplateLinkage(sym)) return templateLinkage; // never use InternalLinkage for variables marked as "extern" if (vd->storage_class & STCextern) return llvm::GlobalValue::ExternalLinkage; } // function else if (FuncDeclaration* fdecl = sym->isFuncDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Function %savailable externally: %s", (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); } assert(fdecl->type->ty == Tfunction); TypeFunction* ft = static_cast<TypeFunction*>(fdecl->type); // intrinsics are always external if (fdecl->llvmInternal == LLVMintrinsic) return llvm::GlobalValue::ExternalLinkage; // generated by inlining semantics run if (fdecl->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // array operations are always template linkage if (fdecl->isArrayOp == 1) return templateLinkage; // template instances should have weak linkage // but only if there's a body, and it's not naked // otherwise we make it external else if (needsTemplateLinkage(fdecl) && fdecl->fbody && !fdecl->naked) return templateLinkage; // extern(C) functions are always external else if (ft->linkage == LINKc) return llvm::GlobalValue::ExternalLinkage; // If a function without a body is nested in another // function, we cannot use internal linkage for that // function (see below about nested functions) // FIXME: maybe there is a better way without emission // of needless symbols? if (!fdecl->fbody) return llvm::GlobalValue::ExternalLinkage; } // class else if (ClassDeclaration* cd = sym->isClassDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Class %savailable externally: %s", (cd->availableExternally ? "" : "not "), vd->toChars()); } // generated by inlining semantics run if (cd->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (needsTemplateLinkage(cd)) return templateLinkage; } else { assert(0 && "not global/function"); } // If the function needs to be defined in the current module, check if it // 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 // referenced from other D modules e.g. in the case of contracts on // interface methods (where __require/__ensure are emitted to the module // where the interface is declared, but an actual interface implementation // can be in a completely different place). if (canInternalize) { if (FuncDeclaration* fd = sym->isFuncDeclaration()) { 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 // referenced directly from outside that function, so we can give // such symbols internal linkage. This holds even if nested indirectly, // such as member functions of aggregates nested in functions. // // Note: This must be checked after things like template member-ness or // symbols nested in templates would get duplicated for each module, // breaking things like // --- // int counter(T)() { static int i; return i++; }" // --- // if instances get emitted in multiple object files because they'd use // different instances of 'i'. // TODO: Check if we are giving away too much inlining potential due to // canInline being overly conservative here. if (canInternalize) { for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent) { FuncDeclaration *fd = parent->isFuncDeclaration(); if (fd && !fd->canInline(fd->needThis())) { // 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; } } } // default to external linkage return llvm::GlobalValue::ExternalLinkage; }