diff --git a/ddmd/typinf.d b/ddmd/typinf.d new file mode 100644 index 0000000000..2889bf5d77 --- /dev/null +++ b/ddmd/typinf.d @@ -0,0 +1,266 @@ +/** + * Compiler implementation of the + * $(LINK2 http://www.dlang.org, D programming language). + * + * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved + * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(DMDSRC _typeinf.d) + */ + +module ddmd.typinf; + +import ddmd.declaration; +import ddmd.dmodule; +import ddmd.dscope; +import ddmd.dclass; +import ddmd.dstruct; +import ddmd.errors; +import ddmd.globals; +import ddmd.gluelayer; +import ddmd.mtype; +import ddmd.visitor; + +version (IN_LLVM) +{ + import ddmd.dsymbol; + extern (C++) void Declaration_codegen(Dsymbol decl); +} + +/**************************************************** + * Get the exact TypeInfo. + */ +extern (C++) void genTypeInfo(Type torig, Scope* sc) +{ + //printf("Type::genTypeInfo() %p, %s\n", this, toChars()); + if (!Type.dtypeinfo) + { + torig.error(Loc(), "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); + fatal(); + } + + Type t = torig.merge2(); // do this since not all Type's are merge'd + if (!t.vtinfo) + { + if (t.isShared()) // does both 'shared' and 'shared const' + t.vtinfo = TypeInfoSharedDeclaration.create(t); + else if (t.isConst()) + t.vtinfo = TypeInfoConstDeclaration.create(t); + else if (t.isImmutable()) + t.vtinfo = TypeInfoInvariantDeclaration.create(t); + else if (t.isWild()) + t.vtinfo = TypeInfoWildDeclaration.create(t); + else + t.vtinfo = getTypeInfoDeclaration(t); + assert(t.vtinfo); + + /* If this has a custom implementation in std/typeinfo, then + * do not generate a COMDAT for it. + */ + if (!builtinTypeInfo(t)) + { + // Generate COMDAT + if (sc) // if in semantic() pass + { + // Find module that will go all the way to an object file + Module m = sc._module.importedFrom; + m.members.push(t.vtinfo); + } + else // if in obj generation pass + { + version (IN_LLVM) + Declaration_codegen(t.vtinfo); + else + toObjFile(t.vtinfo, global.params.multiobj); + } + } + } + if (!torig.vtinfo) + torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's + assert(torig.vtinfo); +} + +extern (C++) Type getTypeInfoType(Type t, Scope* sc) +{ + assert(t.ty != Terror); + genTypeInfo(t, sc); + return t.vtinfo.type; +} + +extern (C++) TypeInfoDeclaration getTypeInfoDeclaration(Type t) +{ + //printf("Type::getTypeInfoDeclaration() %s\n", t.toChars()); + switch (t.ty) + { + case Tpointer: + return TypeInfoPointerDeclaration.create(t); + case Tarray: + return TypeInfoArrayDeclaration.create(t); + case Tsarray: + return TypeInfoStaticArrayDeclaration.create(t); + case Taarray: + return TypeInfoAssociativeArrayDeclaration.create(t); + case Tstruct: + return TypeInfoStructDeclaration.create(t); + case Tvector: + return TypeInfoVectorDeclaration.create(t); + case Tenum: + return TypeInfoEnumDeclaration.create(t); + case Tfunction: + return TypeInfoFunctionDeclaration.create(t); + case Tdelegate: + return TypeInfoDelegateDeclaration.create(t); + case Ttuple: + return TypeInfoTupleDeclaration.create(t); + case Tclass: + if ((cast(TypeClass)t).sym.isInterfaceDeclaration()) + return TypeInfoInterfaceDeclaration.create(t); + else + return TypeInfoClassDeclaration.create(t); + + default: + return TypeInfoDeclaration.create(t); + } +} + +extern (C++) bool isSpeculativeType(Type t) +{ + extern (C++) final class SpeculativeTypeVisitor : Visitor + { + alias visit = super.visit; + public: + bool result; + + extern (D) this() + { + } + + override void visit(Type t) + { + Type tb = t.toBasetype(); + if (tb != t) + tb.accept(this); + } + + override void visit(TypeNext t) + { + if (t.next) + t.next.accept(this); + } + + override void visit(TypeBasic t) + { + } + + override void visit(TypeVector t) + { + t.basetype.accept(this); + } + + override void visit(TypeAArray t) + { + t.index.accept(this); + visit(cast(TypeNext)t); + } + + override void visit(TypeFunction t) + { + visit(cast(TypeNext)t); + // Currently TypeInfo_Function doesn't store parameter types. + } + + override void visit(TypeStruct t) + { + StructDeclaration sd = t.sym; + if (auto ti = sd.isInstantiated()) + { + if (!ti.needsCodegen()) + { + if (ti.minst || sd.requestTypeInfo) + return; + + /* Bugzilla 14425: TypeInfo_Struct would refer the members of + * struct (e.g. opEquals via xopEquals field), so if it's instantiated + * in speculative context, TypeInfo creation should also be + * stopped to avoid 'unresolved symbol' linker errors. + */ + /* When -debug/-unittest is specified, all of non-root instances are + * automatically changed to speculative, and here is always reached + * from those instantiated non-root structs. + * Therefore, if the TypeInfo is not auctually requested, + * we have to elide its codegen. + */ + result |= true; + return; + } + } + else + { + //assert(!sd.inNonRoot() || sd.requestTypeInfo); // valid? + } + } + + override void visit(TypeClass t) + { + ClassDeclaration sd = t.sym; + if (auto ti = sd.isInstantiated()) + { + if (!ti.needsCodegen() && !ti.minst) + { + result |= true; + } + } + } + + + override void visit(TypeTuple t) + { + if (t.arguments) + { + for (size_t i = 0; i < t.arguments.dim; i++) + { + Type tprm = (*t.arguments)[i].type; + if (tprm) + tprm.accept(this); + if (result) + return; + } + } + } + } + + scope SpeculativeTypeVisitor v = new SpeculativeTypeVisitor(); + t.accept(v); + return v.result; +} + +/* ========================================================================= */ + +/* These decide if there's an instance for them already in std.typeinfo, + * because then the compiler doesn't need to build one. + */ +extern (C++) static bool builtinTypeInfo(Type t) +{ + version (IN_LLVM) + { + // FIXME: if I enable for Tclass, the way LDC does typeinfo will cause + // a bunch of linker errors to missing ClassInfo init symbols. + if (t.isTypeBasic() || t.ty == Tnull) + return !t.mod; + } + else + { + if (t.isTypeBasic() || t.ty == Tclass || t.ty == Tnull) + return !t.mod; + } + if (t.ty == Tarray) + { + Type next = t.nextOf(); + // strings are so common, make them builtin + return !t.mod && + (next.isTypeBasic() !is null && !next.mod || + next.ty == Tchar && next.mod == MODimmutable || + next.ty == Tchar && next.mod == MODconst); + } + return false; +} diff --git a/gen/declarations.cpp b/gen/declarations.cpp index 816e935692..934a8b9337 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -30,86 +30,6 @@ ////////////////////////////////////////////////////////////////////////////// -namespace { -// from dmd/src/typinf.c -bool isSpeculativeType(Type *t) { - class SpeculativeTypeVisitor : public Visitor { - public: - bool result; - - SpeculativeTypeVisitor() : result(false) {} - - using Visitor::visit; - void visit(Type *t) override { - Type *tb = t->toBasetype(); - if (tb != t) { - tb->accept(this); - } - } - void visit(TypeNext *t) override { - if (t->next) { - t->next->accept(this); - } - } - void visit(TypeBasic *t) override {} - void visit(TypeVector *t) override { t->basetype->accept(this); } - void visit(TypeAArray *t) override { - t->index->accept(this); - visit((TypeNext *)t); - } - void visit(TypeFunction *t) override { - visit((TypeNext *)t); - // Currently TypeInfo_Function doesn't store parameter types. - } - void visit(TypeStruct *t) override { - StructDeclaration *sd = t->sym; - if (TemplateInstance *ti = sd->isInstantiated()) { - if (!ti->needsCodegen()) { - if (ti->minst || sd->requestTypeInfo) { - return; - } - - /* Bugzilla 14425: TypeInfo_Struct would refer the members of - * struct (e.g. opEquals via xopEquals field), so if it's instantiated - * in speculative context, TypeInfo creation should also be - * stopped to avoid 'unresolved symbol' linker errors. - */ - /* When -debug/-unittest is specified, all of non-root instances are - * automatically changed to speculative, and here is always reached - * from those instantiated non-root structs. - * Therefore, if the TypeInfo is not auctually requested, - * we have to elide its codegen. - */ - result |= true; - return; - } - } else { - // assert(!sd->inNonRoot() || sd->requestTypeInfo); // valid? - } - } - void visit(TypeClass *t) override {} - void visit(TypeTuple *t) override { - if (t->arguments) { - for (size_t i = 0; i < t->arguments->dim; i++) { - Type *tprm = (*t->arguments)[i]->type; - if (tprm) { - tprm->accept(this); - } - if (result) { - return; - } - } - } - } - }; - SpeculativeTypeVisitor v; - t->accept(&v); - return v.result; -} -} - -////////////////////////////////////////////////////////////////////////////// - class CodegenVisitor : public Visitor { IRState *irs; diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 2c5680747b..a63cbf0242 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -53,129 +53,21 @@ #include #include -static bool builtinTypeInfo(Type *t); FuncDeclaration *search_toString(StructDeclaration *sd); -namespace { -TypeInfoDeclaration *createUnqualified(Type *t) { - switch (t->ty) { - case Tpointer: - return TypeInfoPointerDeclaration::create(t); - case Tarray: - return TypeInfoArrayDeclaration::create(t); - case Tsarray: - return TypeInfoStaticArrayDeclaration::create(t); - case Taarray: - return TypeInfoAssociativeArrayDeclaration::create(t); - case Tstruct: - return TypeInfoStructDeclaration::create(t); - case Tvector: - return TypeInfoVectorDeclaration::create(t); - case Tenum: - return TypeInfoEnumDeclaration::create(t); - case Tfunction: - return TypeInfoFunctionDeclaration::create(t); - case Tdelegate: - return TypeInfoDelegateDeclaration::create(t); - case Ttuple: - return TypeInfoTupleDeclaration::create(t); - case Tclass: - if ((static_cast(t))->sym->isInterfaceDeclaration()) { - return TypeInfoInterfaceDeclaration::create(t); - } else { - return TypeInfoClassDeclaration::create(t); - } - default: - return TypeInfoDeclaration::create(t); - } -} -} +// defined in ddmd/typinf.d: +void genTypeInfo(Type *torig, Scope *sc); +bool builtinTypeInfo(Type *t); TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(Type *torig, Scope *sc) { IF_LOG Logger::println("Type::getTypeInfo(): %s", torig->toChars()); LOG_SCOPE - if (!Type::dtypeinfo) { - torig->error(Loc(), "TypeInfo not found. object.d may be incorrectly " - "installed or corrupt, compile with -v switch"); - fatal(); - } + genTypeInfo(torig, sc); - Type *t = torig->merge2(); // do this since not all Type's are merge'd - if (!t->vtinfo) { - if (t->isShared()) { // does both 'shared' and 'shared const' - t->vtinfo = TypeInfoSharedDeclaration::create(t); - } else if (t->isConst()) { - t->vtinfo = TypeInfoConstDeclaration::create(t); - } else if (t->isImmutable()) { - t->vtinfo = TypeInfoInvariantDeclaration::create(t); - } else if (t->isWild()) { - t->vtinfo = TypeInfoWildDeclaration::create(t); - } else { - t->vtinfo = createUnqualified(t); - } - assert(t->vtinfo); - torig->vtinfo = t->vtinfo; - - /* If this has a custom implementation in std/typeinfo, then - * do not generate a COMDAT for it. - */ - if (!builtinTypeInfo(t)) { // Generate COMDAT - if (sc) // if in semantic() pass - { - // Find module that will go all the way to an object file - Module *m = sc->module->importedFrom; - m->members->push(t->vtinfo); - - semanticTypeInfo(sc, t); - } else // if in obj generation pass - { - Declaration_codegen(t->vtinfo); - } - } - } - if (!torig->vtinfo) { - torig->vtinfo = - t->vtinfo; // Types aren't merged, but we can share the vtinfo's - } - assert(torig->vtinfo); return torig->vtinfo; } -Type *getTypeInfoType(Type *t, Scope *sc) { - assert(t->ty != Terror); - getOrCreateTypeInfoDeclaration(t, sc); - return t->vtinfo->type; -} - -/* ========================================================================= */ - -/* These decide if there's an instance for them already in std.typeinfo, - * because then the compiler doesn't need to build one. - */ - -static bool builtinTypeInfo(Type *t) { -#if 0 - // FIXME if I enable for Tclass, the way LDC does typeinfo will cause a - // bunch of linker errors to missing class typeinfo definitions. - if (t->isTypeBasic() || t->ty == Tclass) - return !t->mod; -#else - if (t->isTypeBasic()) { - return !t->mod; - } -#endif - - if (t->ty == Tarray) { - Type *next = t->nextOf(); - return !t->mod && ((next->isTypeBasic() != nullptr && !next->mod) || - // strings are so common, make them builtin - (next->ty == Tchar && next->mod == MODimmutable) || - (next->ty == Tchar && next->mod == MODconst)); - } - return false; -} - /* ========================================================================= */ ////////////////////////////////////////////////////////////////////////////// diff --git a/gen/typinf.h b/gen/typinf.h index 6a0f0cdd88..2bf69fd1b2 100644 --- a/gen/typinf.h +++ b/gen/typinf.h @@ -24,6 +24,9 @@ void DtoResolveTypeInfo(TypeInfoDeclaration *tid); TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(Type *t, Scope *sc); void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p); void TypeInfoClassDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p); + +// defined in ddmd/typinf.d: Type *getTypeInfoType(Type *t, Scope *sc); +bool isSpeculativeType(Type *t); #endif