mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 01:20:51 +03:00
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:
parent
162c264450
commit
fd7c075e3b
4 changed files with 273 additions and 192 deletions
266
ddmd/typinf.d
Normal file
266
ddmd/typinf.d
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
116
gen/typinf.cpp
116
gen/typinf.cpp
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue