Use DMD's typinf.d directly

Instead of letting our old copy silently go more and more out-of-sync.
In this case, we missed the upstream fix wrt. skipping the declaration of
ClassInfos for speculative class types.

There are 2 noteworthy functional changes for function
`getOrCreateTypeInfoDeclaration()`:

1) The old version always overwrote `torig->vtinfo` with `t->vtinfo` when
   declaring a new TypeInfo, whereas upstream's `genTypeInfo()` only sets
   it if it was null before.

2) The old version called `semanticTypeInfo()` during a semantic pass,
   upstream doesn't.

The LDC-specific exception for class types in `builtinTypeInfo()` is still
required.

Fixes dmd-testsuite's runnable/b16278.d.
This commit is contained in:
Martin 2017-03-05 14:28:56 +01:00
parent 162c264450
commit fd7c075e3b
4 changed files with 273 additions and 192 deletions

266
ddmd/typinf.d Normal file
View file

@ -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;
}

View file

@ -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 { class CodegenVisitor : public Visitor {
IRState *irs; IRState *irs;

View file

@ -53,129 +53,21 @@
#include <cstdio> #include <cstdio>
#include <ir/irtypeclass.h> #include <ir/irtypeclass.h>
static bool builtinTypeInfo(Type *t);
FuncDeclaration *search_toString(StructDeclaration *sd); FuncDeclaration *search_toString(StructDeclaration *sd);
namespace { // defined in ddmd/typinf.d:
TypeInfoDeclaration *createUnqualified(Type *t) { void genTypeInfo(Type *torig, Scope *sc);
switch (t->ty) { bool builtinTypeInfo(Type *t);
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<TypeClass *>(t))->sym->isInterfaceDeclaration()) {
return TypeInfoInterfaceDeclaration::create(t);
} else {
return TypeInfoClassDeclaration::create(t);
}
default:
return TypeInfoDeclaration::create(t);
}
}
}
TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(Type *torig, Scope *sc) { TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(Type *torig, Scope *sc) {
IF_LOG Logger::println("Type::getTypeInfo(): %s", torig->toChars()); IF_LOG Logger::println("Type::getTypeInfo(): %s", torig->toChars());
LOG_SCOPE LOG_SCOPE
if (!Type::dtypeinfo) { genTypeInfo(torig, sc);
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 = 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; 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;
}
/* ========================================================================= */ /* ========================================================================= */
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View file

@ -24,6 +24,9 @@ void DtoResolveTypeInfo(TypeInfoDeclaration *tid);
TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(Type *t, Scope *sc); TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(Type *t, Scope *sc);
void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p); void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p);
void TypeInfoClassDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p); void TypeInfoClassDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p);
// defined in ddmd/typinf.d:
Type *getTypeInfoType(Type *t, Scope *sc); Type *getTypeInfoType(Type *t, Scope *sc);
bool isSpeculativeType(Type *t);
#endif #endif