mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
1871 lines
54 KiB
C++
1871 lines
54 KiB
C++
/**
|
|
* Test the C++ compiler interface of the
|
|
* $(LINK2 https://www.dlang.org, D programming language).
|
|
*
|
|
* Copyright: Copyright (C) 2017-2023 by The D Language Foundation, All Rights Reserved
|
|
* Authors: Iain Buclaw
|
|
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
|
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/tests/cxxfrontend.c, _cxxfrontend.c)
|
|
*/
|
|
|
|
#include "root/array.h"
|
|
#include "root/bitarray.h"
|
|
#include "root/complex_t.h"
|
|
#include "root/ctfloat.h"
|
|
#include "root/dcompat.h"
|
|
#include "root/dsystem.h"
|
|
#include "root/filename.h"
|
|
#include "root/longdouble.h"
|
|
#include "root/optional.h"
|
|
#include "common/outbuffer.h"
|
|
#include "root/port.h"
|
|
#include "root/rmem.h"
|
|
|
|
#include "rootobject.h"
|
|
#include "aggregate.h"
|
|
#include "aliasthis.h"
|
|
#include "argtypes.h"
|
|
#include "arraytypes.h"
|
|
#include "ast_node.h"
|
|
#include "attrib.h"
|
|
#include "compiler.h"
|
|
#include "cond.h"
|
|
#include "ctfe.h"
|
|
#include "declaration.h"
|
|
#include "doc.h"
|
|
#include "dsymbol.h"
|
|
#include "enum.h"
|
|
#include "errors.h"
|
|
#include "expression.h"
|
|
#include "globals.h"
|
|
#include "hdrgen.h"
|
|
#include "identifier.h"
|
|
#include "id.h"
|
|
#include "import.h"
|
|
#include "init.h"
|
|
#include "json.h"
|
|
#include "mangle.h"
|
|
#include "module.h"
|
|
#include "mtype.h"
|
|
#include "nspace.h"
|
|
#include "objc.h"
|
|
#include "scope.h"
|
|
#include "statement.h"
|
|
#include "staticassert.h"
|
|
#include "target.h"
|
|
#include "template.h"
|
|
#include "tokens.h"
|
|
#include "typinf.h"
|
|
#include "version.h"
|
|
#include "visitor.h"
|
|
|
|
/**********************************/
|
|
|
|
extern "C" int rt_init();
|
|
extern "C" void gc_disable();
|
|
|
|
static void frontend_init()
|
|
{
|
|
rt_init();
|
|
gc_disable();
|
|
|
|
global._init();
|
|
global.compileEnv.vendor = "Front-End Tester";
|
|
global.params.objname = NULL;
|
|
|
|
target.os = Target::OS_linux;
|
|
target.isX86_64 = true;
|
|
target.cpu = CPU::native;
|
|
target._init(global.params);
|
|
|
|
Type::_init();
|
|
Id::initialize();
|
|
Module::_init();
|
|
Expression::_init();
|
|
Objc::_init();
|
|
CTFloat::initialize();
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
extern "C" int rt_term();
|
|
extern "C" void gc_enable();
|
|
|
|
static void frontend_term()
|
|
{
|
|
gc_enable();
|
|
rt_term();
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_tokens()
|
|
{
|
|
// First valid TOK value
|
|
assert((unsigned)TOK::leftParenthesis == 1);
|
|
assert(strcmp(Token::toChars(TOK::leftParenthesis), "(") == 0);
|
|
|
|
// Last valid TOK value
|
|
assert((unsigned)TOK::attribute__ == (unsigned)TOK::MAX - 1);
|
|
assert(strcmp(Token::toChars(TOK::attribute__), "__attribute__") == 0);
|
|
}
|
|
|
|
void test_compiler_globals()
|
|
{
|
|
// only check constant prefix of version
|
|
assert(strncmp(global.versionChars(), "v2.", 3) == 0);
|
|
unsigned versionNumber = global.versionNumber();
|
|
assert(versionNumber >= 2060 && versionNumber <= 3000);
|
|
|
|
assert(strcmp(target.architectureName.ptr, "X86_64") == 0 ||
|
|
strcmp(target.architectureName.ptr, "X86") == 0);
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
class TestVisitor : public Visitor
|
|
{
|
|
using Visitor::visit;
|
|
|
|
public:
|
|
bool expr;
|
|
bool package;
|
|
bool stmt;
|
|
bool type;
|
|
bool aggr;
|
|
bool attrib;
|
|
bool decl;
|
|
bool typeinfo;
|
|
bool idexpr;
|
|
bool function;
|
|
|
|
TestVisitor() : expr(false), package(false), stmt(false), type(false),
|
|
aggr(false), attrib(false), decl(false), typeinfo(false), idexpr(false),
|
|
function(false)
|
|
{
|
|
}
|
|
|
|
void visit(Expression *) override
|
|
{
|
|
expr = true;
|
|
}
|
|
|
|
void visit(IdentifierExp *) override
|
|
{
|
|
idexpr = true;
|
|
}
|
|
|
|
void visit(Package *) override
|
|
{
|
|
package = true;
|
|
}
|
|
|
|
void visit(Statement *) override
|
|
{
|
|
stmt = true;
|
|
}
|
|
|
|
void visit(AttribDeclaration *) override
|
|
{
|
|
attrib = true;
|
|
}
|
|
|
|
void visit(Declaration *) override
|
|
{
|
|
decl = true;
|
|
}
|
|
|
|
void visit(AggregateDeclaration *) override
|
|
{
|
|
aggr = true;
|
|
}
|
|
|
|
void visit(TypeNext *) override
|
|
{
|
|
type = true;
|
|
}
|
|
|
|
void visit(TypeInfoDeclaration *) override
|
|
{
|
|
typeinfo = true;
|
|
}
|
|
|
|
void visit(FuncDeclaration *) override
|
|
{
|
|
function = true;
|
|
}
|
|
};
|
|
|
|
void test_visitors()
|
|
{
|
|
TestVisitor tv;
|
|
Loc loc;
|
|
Identifier *ident = Identifier::idPool("test");
|
|
|
|
IntegerExp *ie = IntegerExp::create(loc, 42, Type::tint32);
|
|
ie->accept(&tv);
|
|
assert(tv.expr == true);
|
|
|
|
IdentifierExp *id = IdentifierExp::create (loc, ident);
|
|
id->accept(&tv);
|
|
assert(tv.idexpr == true);
|
|
|
|
Module *mod = Module::create("test", ident, 0, 0);
|
|
assert(mod->isModule() == mod);
|
|
mod->accept(&tv);
|
|
assert(tv.package == true);
|
|
|
|
ExpStatement *es = ExpStatement::create(loc, ie);
|
|
assert(es->isExpStatement() == es);
|
|
es->accept(&tv);
|
|
assert(tv.stmt == true);
|
|
|
|
TypePointer *tp = TypePointer::create(Type::tvoid);
|
|
assert(dmd::hasPointers(tp) == true);
|
|
tp->accept(&tv);
|
|
assert(tv.type == true);
|
|
|
|
LinkDeclaration *ld = LinkDeclaration::create(loc, LINK::d, NULL);
|
|
assert(ld->isAttribDeclaration() == static_cast<AttribDeclaration *>(ld));
|
|
assert(ld->linkage == LINK::d);
|
|
ld->accept(&tv);
|
|
assert(tv.attrib == true);
|
|
|
|
ClassDeclaration *cd = ClassDeclaration::create(loc, Identifier::idPool("TypeInfo"), NULL, NULL, true);
|
|
assert(cd->isClassDeclaration() == cd);
|
|
assert(cd->vtblOffset() == 1);
|
|
cd->accept(&tv);
|
|
assert(tv.aggr == true);
|
|
|
|
AliasDeclaration *ad = AliasDeclaration::create(loc, ident, tp);
|
|
assert(ad->isAliasDeclaration() == ad);
|
|
ad->storage_class = STCabstract;
|
|
assert(ad->isAbstract() == true);
|
|
ad->accept(&tv);
|
|
assert(tv.decl == true);
|
|
|
|
cd = ClassDeclaration::create(loc, Identifier::idPool("TypeInfo_Pointer"), NULL, NULL, true);
|
|
TypeInfoPointerDeclaration *ti = TypeInfoPointerDeclaration::create(tp);
|
|
assert(ti->isTypeInfoDeclaration() == ti);
|
|
assert(ti->tinfo == tp);
|
|
ti->accept(&tv);
|
|
assert(tv.typeinfo == true);
|
|
|
|
Parameters *args = new Parameters;
|
|
TypeFunction *tf = TypeFunction::create(args, Type::tvoid, VARARGnone, LINK::c);
|
|
FuncDeclaration *fd = FuncDeclaration::create(Loc (), Loc (), Identifier::idPool("test"),
|
|
STCextern, tf);
|
|
assert(fd->isFuncDeclaration() == fd);
|
|
assert(fd->type == tf);
|
|
fd->accept(&tv);
|
|
assert(tv.function == true);
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_semantic()
|
|
{
|
|
/* Mini object.d source. Module::parse will add internal members also. */
|
|
const char *buf =
|
|
"module object;\n"
|
|
"class Object { }\n"
|
|
"class Throwable { }\n"
|
|
"class Error : Throwable { this(immutable(char)[]); }";
|
|
|
|
DArray<unsigned char> src = DArray<unsigned char>(strlen(buf), (unsigned char *)mem.xstrdup(buf));
|
|
|
|
Module *m = Module::create("object.d", Identifier::idPool("object"), 0, 0);
|
|
|
|
unsigned errors = global.startGagging();
|
|
|
|
m->src = src;
|
|
m->parse();
|
|
m->importedFrom = m;
|
|
dmd::importAll(m, NULL);
|
|
dmd::dsymbolSemantic(m, NULL);
|
|
dmd::semantic2(m, NULL);
|
|
dmd::semantic3(m, NULL);
|
|
|
|
Dsymbol *s = dmd::search(m, Loc(), Identifier::idPool("Error"));
|
|
assert(s);
|
|
AggregateDeclaration *ad = s->isAggregateDeclaration();
|
|
assert(ad && ad->ctor && ad->sizeok == Sizeok::done);
|
|
CtorDeclaration *ctor = ad->ctor->isCtorDeclaration();
|
|
assert(ctor->isMember() && !ctor->isNested());
|
|
assert(0 == strcmp(ctor->type->toChars(), "Error(string)"));
|
|
|
|
ClassDeclaration *cd = ad->isClassDeclaration();
|
|
assert(cd && cd->hasMonitor());
|
|
|
|
assert(!global.endGagging(errors));
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_skip_importall()
|
|
{
|
|
/* Similar to test_semantic(), but importAll step is skipped. */
|
|
const char *buf =
|
|
"module rootobject;\n"
|
|
"import object;\n"
|
|
"class RootObject : Object { }";
|
|
|
|
DArray<unsigned char> src = DArray<unsigned char>(strlen(buf), (unsigned char *)mem.xstrdup(buf));
|
|
|
|
Module *m = Module::create("rootobject.d", Identifier::idPool("rootobject"), 0, 0);
|
|
|
|
unsigned errors = global.startGagging();
|
|
|
|
m->src = src;
|
|
m->parse();
|
|
m->importedFrom = m;
|
|
dmd::dsymbolSemantic(m, NULL);
|
|
dmd::semantic2(m, NULL);
|
|
dmd::semantic3(m, NULL);
|
|
|
|
assert(!global.endGagging(errors));
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_expression()
|
|
{
|
|
Loc loc;
|
|
IntegerExp *ie = IntegerExp::create(loc, 42, Type::tint32);
|
|
Expression *e = dmd::ctfeInterpret(ie);
|
|
|
|
assert(e);
|
|
assert(e->isConst());
|
|
|
|
Optional<bool> res = e->toBool();
|
|
assert(res.get());
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_target()
|
|
{
|
|
assert(target.isVectorOpSupported(Type::tint32, EXP::pow));
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_parameters()
|
|
{
|
|
Parameters *args = new Parameters;
|
|
args->push(Parameter::create(Loc(), STCundefined, Type::tint32, NULL, NULL, NULL));
|
|
args->push(Parameter::create(Loc(), STCundefined, Type::tint64, NULL, NULL, NULL));
|
|
|
|
TypeFunction *tf = TypeFunction::create(args, Type::tvoid, VARARGnone, LINK::c);
|
|
|
|
assert(tf->parameterList.length() == 2);
|
|
assert(tf->parameterList[0]->type == Type::tint32);
|
|
assert(tf->parameterList[1]->type == Type::tint64);
|
|
assert(!tf->isDstyleVariadic());
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_types()
|
|
{
|
|
Parameters *args = new Parameters;
|
|
StorageClass stc = STCnothrow|STCproperty|STCreturn|STCreturninferred|STCtrusted;
|
|
TypeFunction *tfunction = TypeFunction::create(args, Type::tvoid, VARARGnone, LINK::d, stc);
|
|
|
|
assert(tfunction->isNothrow());
|
|
assert(!tfunction->isNogc());
|
|
assert(tfunction->isProperty());
|
|
assert(!tfunction->isRef());
|
|
tfunction->isRef(true);
|
|
assert(tfunction->isRef());
|
|
assert(tfunction->isReturn());
|
|
assert(!tfunction->isScopeQual());
|
|
assert(tfunction->isReturnInferred());
|
|
assert(!tfunction->isScopeInferred());
|
|
assert(tfunction->linkage == LINK::d);
|
|
assert(tfunction->trust == TRUST::trusted);
|
|
assert(tfunction->purity == PURE::impure);
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_location()
|
|
{
|
|
Loc loc = Loc::singleFilename("app.d");
|
|
assert(strcmp(loc.toChars(true, MessageStyle::digitalmars), "app.d") == 0);
|
|
assert(strcmp(loc.toChars(true, MessageStyle::gnu), "app.d") == 0);
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
void test_array()
|
|
{
|
|
Array<double> array;
|
|
array.setDim(4);
|
|
array.shift(10);
|
|
array.push(20);
|
|
array[2] = 15;
|
|
assert(array[0] == 10);
|
|
assert(array.find(10) == 0);
|
|
assert(array.find(20) == 5);
|
|
assert(!array.contains(99));
|
|
array.remove(1);
|
|
assert(array.length == 5);
|
|
assert(array[1] == 15);
|
|
assert(array.pop() == 20);
|
|
assert(array.length == 4);
|
|
array.insert(1, 30);
|
|
assert(array[1] == 30);
|
|
assert(array[2] == 15);
|
|
|
|
Array<int> arrayA;
|
|
array.setDim(0);
|
|
int buf[3] = {10, 15, 20};
|
|
arrayA.push(buf[0]);
|
|
arrayA.push(buf[1]);
|
|
arrayA.push(buf[2]);
|
|
assert(memcmp(arrayA.tdata(), buf, sizeof(buf)) == 0);
|
|
Array<int> *arrayPtr = arrayA.copy();
|
|
assert(arrayPtr);
|
|
assert(memcmp(arrayPtr->tdata(), arrayA.tdata(), arrayA.length * sizeof(int)) == 0);
|
|
assert(arrayPtr->tdata() != arrayA.tdata());
|
|
|
|
arrayPtr->setDim(0);
|
|
int buf2[2] = {100, 200};
|
|
arrayPtr->push(buf2[0]);
|
|
arrayPtr->push(buf2[1]);
|
|
|
|
arrayA.append(arrayPtr);
|
|
assert(memcmp(arrayA.tdata() + 3, buf2, sizeof(buf2)) == 0);
|
|
arrayA.insert(0, arrayPtr);
|
|
assert(arrayA[0] == 100);
|
|
assert(arrayA[1] == 200);
|
|
assert(arrayA[2] == 10);
|
|
assert(arrayA[3] == 15);
|
|
assert(arrayA[4] == 20);
|
|
assert(arrayA[5] == 100);
|
|
assert(arrayA[6] == 200);
|
|
|
|
arrayA.zero();
|
|
for (size_t i = 0; i < arrayA.length; i++)
|
|
assert(arrayA[i] == 0);
|
|
|
|
Array<IntegerExp *> arrayInts;
|
|
arrayInts.push(IntegerExp::create(Loc(), 10, Type::tint32));
|
|
arrayInts.shift(IntegerExp::create(Loc(), 200, Type::tint32));
|
|
arrayInts.push(IntegerExp::create(Loc(), 15, Type::tint32));
|
|
arrayInts.shift(IntegerExp::create(Loc(), 100, Type::tint32));
|
|
arrayInts.push(IntegerExp::create(Loc(), 20, Type::tint32));
|
|
|
|
assert(strcmp(arrayInts.toChars(), "[100,200,10,15,20]") == 0);
|
|
}
|
|
|
|
void test_outbuffer()
|
|
{
|
|
OutBuffer buf;
|
|
dmd::mangleToBuffer(Type::tint64, buf);
|
|
assert(strcmp(buf.peekChars(), "l") == 0);
|
|
buf.reset();
|
|
|
|
buf.reserve(16);
|
|
buf.writestring("hello");
|
|
buf.writeByte('!');
|
|
buf.write(&buf);
|
|
buf.writenl();
|
|
assert(buf.length() == 13);
|
|
|
|
const char *data = buf.extractChars();
|
|
assert(buf.length() == 0);
|
|
assert(strcmp(data, "hello!hello!\n") == 0);
|
|
}
|
|
|
|
void test_cppmangle()
|
|
{
|
|
// Based off runnable_cxx/cppa.d.
|
|
const char *buf =
|
|
"module cppa;\n"
|
|
"extern (C++):\n"
|
|
"class Base { void based() { } }\n"
|
|
"interface Interface { int MethodCPP(); int MethodD(); }\n"
|
|
"class Derived : Base, Interface { int MethodCPP(); int MethodD() { return 3; } }";
|
|
|
|
DArray<unsigned char> src = DArray<unsigned char>(strlen(buf), (unsigned char *)mem.xstrdup(buf));
|
|
|
|
Module *m = Module::create("cppa.d", Identifier::idPool("cppa"), 0, 0);
|
|
|
|
unsigned errors = global.startGagging();
|
|
FuncDeclaration *fd;
|
|
const char *mangle;
|
|
|
|
m->src = src;
|
|
m->parse();
|
|
m->importedFrom = m;
|
|
dmd::importAll(m, NULL);
|
|
dmd::dsymbolSemantic(m, NULL);
|
|
dmd::semantic2(m, NULL);
|
|
dmd::semantic3(m, NULL);
|
|
|
|
Dsymbol *s = dmd::search(m, Loc(), Identifier::idPool("Derived"));
|
|
assert(s);
|
|
ClassDeclaration *cd = s->isClassDeclaration();
|
|
assert(cd && cd->sizeok == Sizeok::done);
|
|
assert(cd->members && cd->members->length == 2);
|
|
assert(cd->vtblInterfaces && cd->vtblInterfaces->length == 1);
|
|
BaseClass *b = (*cd->vtblInterfaces)[0];
|
|
|
|
fd = (*cd->members)[0]->isFuncDeclaration();
|
|
assert(fd);
|
|
mangle = dmd::cppThunkMangleItanium(fd, b->offset);
|
|
assert(strcmp(mangle, "_ZThn8_N7Derived9MethodCPPEv") == 0);
|
|
|
|
fd = (*cd->members)[1]->isFuncDeclaration();
|
|
assert(fd);
|
|
mangle = dmd::cppThunkMangleItanium(fd, b->offset);
|
|
assert(strcmp(mangle, "_ZThn8_N7Derived7MethodDEv") == 0);
|
|
|
|
assert(!global.endGagging(errors));
|
|
}
|
|
|
|
void test_module()
|
|
{
|
|
unsigned errors = global.startGagging();
|
|
Module *mod = Module::load(Loc(), NULL, Identifier::idPool("doesnotexist.d"));
|
|
assert(mod == NULL);
|
|
assert(global.endGagging(errors));
|
|
}
|
|
|
|
void test_optional()
|
|
{
|
|
Optional<bool> opt = Optional<bool>::create(true);
|
|
assert(!opt.isEmpty());
|
|
assert(opt.isPresent());
|
|
assert(opt.get() == true);
|
|
assert(opt.hasValue(true));
|
|
}
|
|
|
|
void test_filename()
|
|
{
|
|
const char *fname = "/a/nice/long/path/to/somefile.d";
|
|
|
|
const char *basename = FileName::name(fname);
|
|
assert(strcmp(basename, "somefile.d") == 0);
|
|
|
|
const char *name = FileName::removeExt(basename);
|
|
assert(strcmp(name, "somefile") == 0);
|
|
|
|
const char *jsonname = FileName::defaultExt(name, json_ext.ptr);
|
|
assert(strcmp(jsonname, "somefile.json") == 0);
|
|
|
|
FileName file = FileName::create("somefile.d");
|
|
assert(FileName::equals(basename, file.toChars()));
|
|
|
|
FileName::free(name);
|
|
FileName::free(jsonname);
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
class MiniGlueVisitor : public Visitor
|
|
{
|
|
using Visitor::visit;
|
|
FuncDeclaration *func;
|
|
public:
|
|
MiniGlueVisitor(FuncDeclaration *func)
|
|
: func(func)
|
|
{
|
|
}
|
|
|
|
void visit(Type *) override { assert(0); }
|
|
void visit(TypeError *t) override { (void)t->ctype; }
|
|
void visit(TypeNull *t) override { (void)t->ctype; }
|
|
void visit(TypeNoreturn *t) override { (void)t->ctype; }
|
|
void visit(TypeBasic *t) override
|
|
{
|
|
switch (t->ty)
|
|
{
|
|
case TY::Tvoid:
|
|
case TY::Tbool:
|
|
case TY::Tint8:
|
|
case TY::Tuns8:
|
|
case TY::Tint16:
|
|
case TY::Tuns16:
|
|
case TY::Tint32:
|
|
case TY::Tuns32:
|
|
case TY::Tint64:
|
|
case TY::Tuns64:
|
|
case TY::Tint128:
|
|
case TY::Tuns128:
|
|
case TY::Tfloat32:
|
|
case TY::Tfloat64:
|
|
case TY::Tfloat80:
|
|
case TY::Timaginary32:
|
|
case TY::Timaginary64:
|
|
case TY::Timaginary80:
|
|
case TY::Tcomplex32:
|
|
case TY::Tcomplex64:
|
|
case TY::Tcomplex80:
|
|
case TY::Tchar:
|
|
case TY::Twchar:
|
|
case TY::Tdchar:
|
|
(void)t->ctype; break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
(void)t->toChars();
|
|
}
|
|
void visit(TypePointer *t) override
|
|
{
|
|
t->next->accept(this);
|
|
(void)t->ctype;
|
|
}
|
|
void visit(TypeDArray *t) override
|
|
{
|
|
t->next->accept(this);
|
|
Type::tsize_t->accept(this);
|
|
(void)t->ctype;
|
|
(void)t->toChars();
|
|
}
|
|
void visit(TypeSArray *t) override
|
|
{
|
|
if (t->dim->isConst() && t->dim->type->isIntegral())
|
|
{
|
|
(void)t->dim->toUInteger();
|
|
t->next->accept(this);
|
|
(void)t->ctype;
|
|
}
|
|
else
|
|
assert(0);
|
|
}
|
|
void visit(TypeVector *t) override
|
|
{
|
|
(void)t->basetype->isTypeSArray()->dim->toUInteger();
|
|
t->elementType()->accept(this);
|
|
if (t->ty == TY::Tvoid)
|
|
Type::tuns8->accept(this);
|
|
(void)t->ctype;
|
|
(void)t->toChars();
|
|
}
|
|
void visit(TypeAArray *t) override
|
|
{
|
|
(void)t->ctype;
|
|
(void)t->toChars();
|
|
}
|
|
void visit(TypeFunction *t) override
|
|
{
|
|
if (t->isDstyleVariadic())
|
|
Type::typeinfotypelist->type->accept(this);
|
|
for (size_t i = 0; i < t->parameterList.length(); i++)
|
|
{
|
|
Parameter *arg = t->parameterList[i];
|
|
(void)arg->storageClass;
|
|
arg->type->accept(this);
|
|
}
|
|
if (t->parameterList.varargs != VARARGvariadic)
|
|
Type::tvoid->accept(this);
|
|
if (t->next != NULL)
|
|
{
|
|
t->next->accept(this);
|
|
(void)t->isRef();
|
|
}
|
|
(void)t->ctype;
|
|
switch (t->linkage)
|
|
{
|
|
case LINK::windows:
|
|
case LINK::c:
|
|
case LINK::cpp:
|
|
case LINK::d:
|
|
case LINK::objc:
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
void visit(TypeDelegate *t) override
|
|
{
|
|
t->next->accept(this);
|
|
Type::tvoidptr->accept(this);
|
|
(void)t->ctype;
|
|
(void)t->toChars();
|
|
}
|
|
void visitUserAttributes(Dsymbol *sym)
|
|
{
|
|
if (!sym->userAttribDecl())
|
|
return;
|
|
Expressions *attrs = dmd::getAttributes(sym->userAttribDecl());
|
|
if (attrs)
|
|
{
|
|
dmd::expandTuples(attrs);
|
|
for (size_t i = 0; i < attrs->length; i++)
|
|
{
|
|
Expression *attr = (*attrs)[i];
|
|
Dsymbol *sym = dmd::toDsymbol(attr->type, 0);
|
|
if (!sym)
|
|
{
|
|
if (TemplateExp *te = attr->isTemplateExp())
|
|
{
|
|
if (!te->td || !te->td->onemember)
|
|
continue;
|
|
sym = te->td->onemember;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
sym->getModule()->accept(this);
|
|
if (attr->op == EXP::call)
|
|
attr = dmd::ctfeInterpret(attr);
|
|
if (attr->op != EXP::structLiteral)
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
void visit(TypeEnum *t) override
|
|
{
|
|
if (t->sym->memtype)
|
|
t->sym->memtype->accept(this);
|
|
if (t->sym->isSpecial())
|
|
{
|
|
(void)t->toChars();
|
|
(void)t->ctype;
|
|
t->sym->accept(this);
|
|
}
|
|
else if (t->sym->ident == NULL)
|
|
{
|
|
(void)t->ctype;
|
|
}
|
|
else
|
|
{
|
|
(void)t->ctype;
|
|
dmd::size(t, t->sym->loc);
|
|
if (t->sym->members)
|
|
{
|
|
for (size_t i = 0; i < t->sym->members->length; i++)
|
|
{
|
|
EnumMember *member = (*t->sym->members)[i]->isEnumMember();
|
|
if (member == NULL)
|
|
continue;
|
|
(void)member->ident->toChars();
|
|
(void)member->value()->toInteger();
|
|
}
|
|
}
|
|
}
|
|
visitUserAttributes(t->sym);
|
|
}
|
|
void visit(TypeStruct *t) override
|
|
{
|
|
t->sym->accept(this);
|
|
(void)t->sym->isUnionDeclaration();
|
|
(void)t->ctype;
|
|
if (t->sym->members)
|
|
{
|
|
(void)t->sym->structsize;
|
|
(void)t->sym->alignment.isDefault();
|
|
(void)t->sym->alignsize;
|
|
(void)t->sym->alignment.get();
|
|
(void)t->sym->isPOD();
|
|
for (size_t i = 0; i < t->sym->members->length; i++)
|
|
{
|
|
Dsymbol *sym = (*t->sym->members)[i];
|
|
if (VarDeclaration *var = sym->isVarDeclaration())
|
|
{
|
|
(void)var->csym;
|
|
(void)var->aliasTuple;
|
|
(void)var->isField();
|
|
(void)var->ident->toChars();
|
|
continue;
|
|
}
|
|
if (AnonDeclaration *ad = sym->isAnonDeclaration())
|
|
{
|
|
(void)ad->isunion;
|
|
(void)ad->loc;
|
|
(void)ad->decl;
|
|
(void)ad->anonoffset;
|
|
(void)ad->anonstructsize;
|
|
(void)ad->anonalignsize;
|
|
continue;
|
|
}
|
|
if (AttribDeclaration *attrib = sym->isAttribDeclaration())
|
|
{
|
|
dmd::include(attrib, NULL);
|
|
continue;
|
|
}
|
|
if (sym->isTemplateMixin() || sym->isNspace())
|
|
{
|
|
if (ScopeDsymbol *scopesym = sym->isScopeDsymbol())
|
|
{
|
|
(void)scopesym->members;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
visitUserAttributes(t->sym);
|
|
}
|
|
void visit(TypeClass *t) override
|
|
{
|
|
t->sym->accept(this);
|
|
(void)t->ctype;
|
|
if (ClassDeclaration *cd = t->sym->isClassDeclaration())
|
|
{
|
|
(void)cd->baseClass;
|
|
cd->type->accept(this);
|
|
if (InterfaceDeclaration *id = cd->isInterfaceDeclaration())
|
|
(void)id->vtblInterfaces->length;
|
|
(void)cd->hasMonitor();
|
|
if (cd->vtblInterfaces)
|
|
{
|
|
for (size_t i = 0; i < cd->vtblInterfaces->length; i++)
|
|
{
|
|
BaseClass *bc = (*cd->vtblInterfaces)[i];
|
|
(void)bc->offset;
|
|
}
|
|
}
|
|
}
|
|
if (t->sym->members)
|
|
{
|
|
(void)t->sym->structsize;
|
|
(void)t->sym->alignsize;
|
|
for (size_t i = 0; i < t->sym->members->length; i++)
|
|
{
|
|
Dsymbol *sym = (*t->sym->members)[i];
|
|
if (VarDeclaration *var = sym->isVarDeclaration())
|
|
{
|
|
(void)var->csym;
|
|
(void)var->aliasTuple;
|
|
(void)var->isField();
|
|
(void)var->ident->toChars();
|
|
continue;
|
|
}
|
|
if (AnonDeclaration *ad = sym->isAnonDeclaration())
|
|
{
|
|
(void)ad->isunion;
|
|
(void)ad->loc;
|
|
(void)ad->decl;
|
|
(void)ad->anonoffset;
|
|
(void)ad->anonstructsize;
|
|
(void)ad->anonalignsize;
|
|
continue;
|
|
}
|
|
if (AttribDeclaration *attrib = sym->isAttribDeclaration())
|
|
{
|
|
dmd::include(attrib, NULL);
|
|
continue;
|
|
}
|
|
if (sym->isTemplateMixin() || sym->isNspace())
|
|
{
|
|
if (ScopeDsymbol *scopesym = sym->isScopeDsymbol())
|
|
{
|
|
(void)scopesym->members;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(void)t->sym->storage_class;
|
|
t->sym->type->accept(this);
|
|
for (size_t i = 0; i < t->sym->vtbl.length; i++)
|
|
t->sym->vtbl[i]->isFuncDeclaration()->accept(this);
|
|
for (size_t i = 0; i < t->sym->baseclasses->length; i++)
|
|
{
|
|
BaseClass *bc = (*t->sym->baseclasses)[i];
|
|
bc->sym->accept(this);
|
|
}
|
|
visitUserAttributes(t->sym);
|
|
}
|
|
void visit(Statement *) override { assert(0); }
|
|
void visit(ScopeGuardStatement *) override { }
|
|
void visit(IfStatement *s) override
|
|
{
|
|
s->condition->accept(this);
|
|
s->condition->type->accept(this);
|
|
if (s->ifbody)
|
|
s->ifbody->accept(this);
|
|
if (s->elsebody)
|
|
s->elsebody->accept(this);
|
|
}
|
|
void visit(PragmaStatement *) override { }
|
|
void visit(WhileStatement *) override { assert(0); }
|
|
void visit(DoStatement *s) override
|
|
{
|
|
s->getRelatedLabeled()->accept(this);
|
|
if (s->_body)
|
|
s->_body->accept(this);
|
|
s->condition->accept(this);
|
|
s->condition->type->accept(this);
|
|
}
|
|
void visit(ForStatement *s) override
|
|
{
|
|
s->getRelatedLabeled()->accept(this);
|
|
if (s->_init)
|
|
s->_init->accept(this);
|
|
if (s->condition)
|
|
{
|
|
s->condition->accept(this);
|
|
s->condition->type->accept(this);
|
|
}
|
|
if (s->_body)
|
|
s->_body->accept(this);
|
|
if (s->increment)
|
|
s->increment->accept(this);
|
|
}
|
|
void visit(ForeachStatement *) override { assert(0); }
|
|
void visit(ForeachRangeStatement *) override { assert(0); }
|
|
void visit(BreakStatement *s) override
|
|
{
|
|
if (s->ident)
|
|
{
|
|
LabelDsymbol *sym = func->searchLabel(s->ident, s->loc);
|
|
LabelStatement *label = sym->statement;
|
|
label->statement->getRelatedLabeled()->accept(this);
|
|
}
|
|
}
|
|
void visit(ContinueStatement *s) override
|
|
{
|
|
if (s->ident)
|
|
{
|
|
LabelDsymbol *sym = func->searchLabel(s->ident, s->loc);
|
|
LabelStatement *label = sym->statement;
|
|
label->statement->accept(this);
|
|
}
|
|
}
|
|
void visit(GotoStatement *s) override
|
|
{
|
|
assert(s->label->statement != NULL);
|
|
assert(s->tf == s->label->statement->tf);
|
|
(void)s->label->ident;
|
|
}
|
|
void visit(LabelStatement *s) override
|
|
{
|
|
LabelDsymbol *sym;
|
|
if (func->returnLabel && func->returnLabel->ident == s->ident)
|
|
sym = func->returnLabel;
|
|
else
|
|
sym = func->searchLabel(s->ident, s->loc);
|
|
sym->statement->accept(this);
|
|
if (sym == func->returnLabel && func->fensure() != NULL)
|
|
func->fensure()->accept(this);
|
|
else if (s->statement)
|
|
s->statement->accept(this);
|
|
}
|
|
void visit(SwitchStatement *s) override
|
|
{
|
|
s->getRelatedLabeled()->accept(this);
|
|
s->condition->accept(this);
|
|
Type *condtype = s->condition->type->toBasetype();
|
|
if (!condtype->isScalar())
|
|
assert(0);
|
|
if (s->cases)
|
|
{
|
|
for (size_t i = 0; i < s->cases->length; i++)
|
|
{
|
|
CaseStatement *cs = (*s->cases)[i];
|
|
if (s->hasVars)
|
|
cs->exp->accept(this);
|
|
}
|
|
s->sdefault->accept(this);
|
|
}
|
|
if (s->_body)
|
|
s->_body->accept(this);
|
|
}
|
|
void visit(CaseStatement *s) override
|
|
{
|
|
s->getRelatedLabeled()->accept(this);
|
|
if (s->exp->type->isScalar())
|
|
s->exp->accept(this);
|
|
else
|
|
(void)s->index;
|
|
if (s->statement)
|
|
s->statement->accept(this);
|
|
}
|
|
void visit(DefaultStatement *s) override
|
|
{
|
|
s->getRelatedLabeled()->accept(this);
|
|
if (s->statement)
|
|
s->statement->accept(this);
|
|
}
|
|
void visit(GotoDefaultStatement *s) override
|
|
{
|
|
s->sw->sdefault->accept(this);
|
|
}
|
|
void visit(GotoCaseStatement *s) override
|
|
{
|
|
s->cs->accept(this);
|
|
}
|
|
void visit(SwitchErrorStatement *s) override
|
|
{
|
|
s->exp->accept(this);
|
|
}
|
|
void visit(ReturnStatement *s) override
|
|
{
|
|
if (s->exp == NULL || s->exp->type->toBasetype()->ty == TY::Tvoid)
|
|
return;
|
|
TypeFunction *tf = func->type->toTypeFunction();
|
|
Type *type = func->tintro != NULL ? func->tintro->nextOf() : tf->nextOf();
|
|
if ((func->isMain() || func->isCMain()) && type->toBasetype()->ty == TY::Tvoid)
|
|
type = Type::tint32;
|
|
if (func->shidden)
|
|
{
|
|
func->accept(this);
|
|
if (func->isNRVO() && func->nrvo_var)
|
|
return;
|
|
StructLiteralExp *sle = NULL;
|
|
if (DotVarExp *dve = (s->exp->isCallExp()
|
|
? s->exp->isCallExp()->e1->isDotVarExp() : NULL))
|
|
{
|
|
if (dve->var->isCtorDeclaration())
|
|
{
|
|
if (CommaExp *ce = dve->e1->isCommaExp())
|
|
{
|
|
DeclarationExp *de = ce->e1->isDeclarationExp();
|
|
VarExp *ve = ce->e2->isVarExp();
|
|
if (de && ve && ve->var == de->declaration &&
|
|
ve->var->storage_class & STCtemp)
|
|
{
|
|
ve->var->accept(this);
|
|
}
|
|
}
|
|
else
|
|
sle = dve->e1->isStructLiteralExp();
|
|
}
|
|
}
|
|
else
|
|
sle = s->exp->isStructLiteralExp();
|
|
if (sle != NULL)
|
|
{
|
|
type->baseElemOf()->isTypeStruct()->sym->accept(this);
|
|
sle->sym = func->shidden;
|
|
}
|
|
s->exp->accept(this);
|
|
}
|
|
else if (tf->next->ty == TY::Tnoreturn)
|
|
s->exp->accept(this);
|
|
else
|
|
s->exp->accept(this);
|
|
}
|
|
void visit(ExpStatement *s) override
|
|
{
|
|
if (s->exp)
|
|
s->exp->accept(this);
|
|
}
|
|
void visit(CompoundStatement *s) override
|
|
{
|
|
if (s->statements == NULL)
|
|
return;
|
|
for (size_t i = 0; i < s->statements->length; i++)
|
|
{
|
|
Statement *statement = (*s->statements)[i];
|
|
if (statement)
|
|
statement->accept(this);
|
|
}
|
|
}
|
|
void visit(UnrolledLoopStatement *s) override
|
|
{
|
|
if (s->statements == NULL)
|
|
return;
|
|
s->getRelatedLabeled()->accept(this);
|
|
for (size_t i = 0; i < s->statements->length; i++)
|
|
{
|
|
Statement *statement = (*s->statements)[i];
|
|
if (statement != NULL)
|
|
statement->accept(this);
|
|
}
|
|
}
|
|
void visit(ScopeStatement *s) override
|
|
{
|
|
if (s->statement == NULL)
|
|
return;
|
|
s->statement->accept(this);
|
|
}
|
|
void visit(WithStatement *s) override
|
|
{
|
|
if (s->wthis)
|
|
{
|
|
s->wthis->accept(this);
|
|
s->wthis->_init->isExpInitializer()->exp->accept(this);
|
|
}
|
|
if (s->_body)
|
|
s->_body->accept(this);
|
|
}
|
|
void visit(ThrowStatement *s) override
|
|
{
|
|
s->exp->type->toBasetype()->isClassHandle()->accept(this);
|
|
s->exp->accept(this);
|
|
}
|
|
void visit(TryCatchStatement *s) override
|
|
{
|
|
if (s->_body)
|
|
s->_body->accept(this);
|
|
if (s->catches)
|
|
{
|
|
for (size_t i = 0; i < s->catches->length; i++)
|
|
{
|
|
Catch *vcatch = (*s->catches)[i];
|
|
vcatch->type->accept(this);
|
|
vcatch->type->isClassHandle()->accept(this);
|
|
if (vcatch->var)
|
|
vcatch->var->accept(this);
|
|
if (vcatch->handler)
|
|
vcatch->handler->accept(this);
|
|
}
|
|
}
|
|
}
|
|
void visit(TryFinallyStatement *s) override
|
|
{
|
|
if (s->_body)
|
|
s->_body->accept(this);
|
|
if (s->finalbody)
|
|
s->finalbody->accept(this);
|
|
}
|
|
void visit(SynchronizedStatement *) override
|
|
{
|
|
assert(0);
|
|
}
|
|
void visit(AsmStatement *) override
|
|
{
|
|
assert(0);
|
|
}
|
|
void visit(GccAsmStatement *s) override
|
|
{
|
|
s->insn->accept(this);
|
|
if (s->args)
|
|
{
|
|
for (size_t i = 0; i < s->args->length; i++)
|
|
{
|
|
(void)(*s->names)[i]->toChars();
|
|
(*s->constraints)[i]->toStringExp()->accept(this);
|
|
(*s->args)[i]->accept(this);
|
|
(void)s->outputargs;
|
|
}
|
|
}
|
|
if (s->clobbers)
|
|
{
|
|
for (size_t i = 0; i < s->clobbers->length; i++)
|
|
(*s->clobbers)[i]->toStringExp()->accept(this);
|
|
}
|
|
if (s->labels)
|
|
{
|
|
for (size_t i = 0; i < s->labels->length; i++)
|
|
{
|
|
(void)(*s->labels)[i]->toChars();
|
|
GotoStatement *gs = (*s->gotos)[i];
|
|
gs->label->statement->accept(this);
|
|
(void)gs->label->ident;
|
|
}
|
|
}
|
|
}
|
|
void visit(ImportStatement *s) override
|
|
{
|
|
if (s->imports == NULL)
|
|
return;
|
|
for (size_t i = 0; i < s->imports->length; i++)
|
|
{
|
|
Dsymbol *dsym = (*s->imports)[i];
|
|
if (dsym != NULL)
|
|
dsym->accept(this);
|
|
}
|
|
}
|
|
void visit(Dsymbol *) override { assert(0); }
|
|
void visit(Module *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->members)
|
|
{
|
|
for (size_t i = 0; i < d->members->length; i++)
|
|
{
|
|
Dsymbol *s = (*d->members)[i];
|
|
s->accept(this);
|
|
}
|
|
ClassDeclarations aclasses;
|
|
dmd::getLocalClasses(d, aclasses);
|
|
for (size_t i = 0; i < d->aimports.length; i++)
|
|
{
|
|
Module *mi = d->aimports[i];
|
|
if (mi->needmoduleinfo)
|
|
mi->accept(this);
|
|
}
|
|
(void)dmd::findGetMembers(d);
|
|
(void)d->sctor;
|
|
(void)d->sdtor;
|
|
(void)d->ssharedctor;
|
|
(void)d->sshareddtor;
|
|
(void)d->sictor;
|
|
(void)d->stest;
|
|
(void)d->needmoduleinfo;
|
|
}
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visit(Import *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->isstatic)
|
|
return;
|
|
if (d->ident == NULL)
|
|
{
|
|
for (size_t i = 0; i < d->names.length; i++)
|
|
{
|
|
d->aliasdecls[i]->accept(this);
|
|
(void)d->aliases[i]->toChars();
|
|
}
|
|
}
|
|
else
|
|
d->mod->accept(this);
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visit(TupleDeclaration *d) override
|
|
{
|
|
for (size_t i = 0; i < d->objects->length; i++)
|
|
{
|
|
RootObject *o = (*d->objects)[i];
|
|
if (o->dyncast() == DYNCAST_EXPRESSION)
|
|
{
|
|
VarExp *ve = ((Expression *) o)->isVarExp();
|
|
if (ve)
|
|
ve->var->accept(this);
|
|
}
|
|
}
|
|
}
|
|
void visit(AttribDeclaration *d) override
|
|
{
|
|
Dsymbols *ds = dmd::include(d, NULL);
|
|
|
|
if (!ds)
|
|
return;
|
|
for (size_t i = 0; i < ds->length; i++)
|
|
(*ds)[i]->accept(this);
|
|
}
|
|
void visit(PragmaDeclaration *d) override
|
|
{
|
|
visit((AttribDeclaration *)d);
|
|
}
|
|
void visit(ConditionalDeclaration *d) override
|
|
{
|
|
(void)d->condition->isVersionCondition();
|
|
visit((AttribDeclaration *)d);
|
|
}
|
|
void visit(Nspace *d) override
|
|
{
|
|
if (dmd::isError(d) || !d->members)
|
|
return;
|
|
for (size_t i = 0; i < d->members->length; i++)
|
|
(*d->members)[i]->accept(this);
|
|
}
|
|
void visit(TemplateDeclaration *d) override
|
|
{
|
|
if (!func || !func->isAuto())
|
|
return;
|
|
Type *tb = func->type->nextOf()->baseElemOf();
|
|
while (tb->ty == TY::Tarray || tb->ty == TY::Tpointer)
|
|
tb = tb->nextOf()->baseElemOf();
|
|
TemplateInstance *ti = NULL;
|
|
if (tb->ty == TY::Tstruct)
|
|
ti = tb->isTypeStruct()->sym->isInstantiated();
|
|
else if (tb->ty == TY::Tclass)
|
|
ti = tb->isTypeClass()->sym->isInstantiated();
|
|
if (ti && ti->tempdecl == d)
|
|
ti->accept(this);
|
|
}
|
|
void visit(TemplateInstance *d) override
|
|
{
|
|
if (dmd::isError(d) || !d->members)
|
|
return;
|
|
if (!d->needsCodegen())
|
|
return;
|
|
for (size_t i = 0; i < d->members->length; i++)
|
|
(*d->members)[i]->accept(this);
|
|
}
|
|
void visit(TemplateMixin *d) override
|
|
{
|
|
if (dmd::isError(d) || !d->members)
|
|
return;
|
|
for (size_t i = 0; i < d->members->length; i++)
|
|
(*d->members)[i]->accept(this);
|
|
}
|
|
void visit(StructDeclaration *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->type->ty == TY::Terror)
|
|
return;
|
|
d->type->accept(this);
|
|
if (d->isAnonymous() || !d->members)
|
|
return;
|
|
(void)d->sinit;
|
|
StructLiteralExp *sle = StructLiteralExp::create(d->loc, d, NULL);
|
|
if (!dmd::fill(d, d->loc, *sle->elements, true))
|
|
assert(0);
|
|
sle->type = d->type;
|
|
sle->accept(this);
|
|
for (size_t i = 0; i < d->members->length; i++)
|
|
(*d->members)[i]->accept(this);
|
|
if (d->xeq && d->xeq != d->xerreq)
|
|
d->xeq->accept(this);
|
|
if (d->xcmp && d->xcmp != d->xerrcmp)
|
|
d->xcmp->accept(this);
|
|
if (d->xhash)
|
|
d->xhash->accept(this);
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visit(ClassDeclaration *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->type->ty == TY::Terror)
|
|
return;
|
|
if (!d->members)
|
|
return;
|
|
for (size_t i = 0; i < d->members->length; i++)
|
|
(*d->members)[i]->accept(this);
|
|
for (size_t i = d->vtblOffset(); i < d->vtbl.length; i++)
|
|
{
|
|
FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration();
|
|
if (!fd || (!fd->fbody && d->isAbstract()))
|
|
continue;
|
|
if (!dmd::functionSemantic(fd))
|
|
return;
|
|
if (!d->isFuncHidden(fd) || fd->isFuture())
|
|
continue;
|
|
for (size_t j = 1; j < d->vtbl.length; j++)
|
|
{
|
|
if (j == i)
|
|
continue;
|
|
FuncDeclaration *fd2 = d->vtbl[j]->isFuncDeclaration();
|
|
if (!fd2->ident->equals(fd->ident))
|
|
continue;
|
|
if (fd2->isFuture())
|
|
continue;
|
|
if (dmd::leastAsSpecialized(fd, fd2, NULL) != MATCH::nomatch ||
|
|
dmd::leastAsSpecialized(fd2, fd, NULL) != MATCH::nomatch)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
(void)d->csym;
|
|
(void)d->vtblSymbol()->csym;
|
|
(void)d->sinit;
|
|
NewExp *ne = NewExp::create(d->loc, NULL, d->type, NULL);
|
|
ne->type = d->type;
|
|
Expression *e = dmd::ctfeInterpret(ne);
|
|
assert(e->op == EXP::classReference);
|
|
ClassReferenceExp *exp = e->isClassReferenceExp();
|
|
ClassDeclaration *cd = exp->originalClass();
|
|
exp->value->stype->accept(this);
|
|
cd->accept(this);
|
|
for (ClassDeclaration *bcd = cd; bcd != NULL; bcd = bcd->baseClass)
|
|
{
|
|
for (size_t i = 0; i < bcd->vtblInterfaces->length; i++)
|
|
{
|
|
BaseClass *bc = (*bcd->vtblInterfaces)[i];
|
|
for (ClassDeclaration *cd2 = cd; 1; cd2 = cd2->baseClass)
|
|
{
|
|
assert(cd2 != NULL);
|
|
for (size_t i = 0; i < cd2->vtblInterfaces->length; i++)
|
|
{
|
|
BaseClass *b = (*cd2->vtblInterfaces)[i];
|
|
if (b == bc)
|
|
break;
|
|
(void)b->sym->vtbl.length;
|
|
}
|
|
for (ClassDeclaration *cd3 = cd2->baseClass; cd3; cd3 = cd3->baseClass)
|
|
{
|
|
for (size_t k = 0; k < cd3->vtblInterfaces->length; k++)
|
|
{
|
|
BaseClass *bs = (*cd3->vtblInterfaces)[k];
|
|
if (bs->fillVtbl(cd2, NULL, 0))
|
|
{
|
|
if (bc == bs)
|
|
break;
|
|
(void)bs->sym->vtbl.length;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(void)bc->offset;
|
|
}
|
|
for (size_t i = 0; i < bcd->fields.length; i++)
|
|
{
|
|
VarDeclaration *vfield = bcd->fields[i];
|
|
size_t index = exp->findFieldIndexByName(vfield);
|
|
Expression *value = (*exp->value->elements)[index];
|
|
if (!value)
|
|
continue;
|
|
vfield->accept(this);
|
|
value->accept(this);
|
|
}
|
|
}
|
|
for (size_t i = d->vtblOffset(); i < d->vtbl.length; i++)
|
|
{
|
|
FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration();
|
|
if (fd && (fd->fbody || !d->isAbstract()))
|
|
visitDeclaration(fd);
|
|
}
|
|
d->type->accept(this);
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visit(InterfaceDeclaration *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->type->ty == TY::Terror)
|
|
return;
|
|
if (!d->members)
|
|
return;
|
|
for (size_t i = 0; i < d->members->length; i++)
|
|
(*d->members)[i]->accept(this);
|
|
(void)d->csym;
|
|
d->type->accept(this);
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visit(EnumDeclaration *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->errors || d->type->ty == TY::Terror)
|
|
return;
|
|
if (d->isAnonymous())
|
|
return;
|
|
TypeEnum *tc = d->type->isTypeEnum();
|
|
if (tc->sym->members && !dmd::isZeroInit(d->type))
|
|
{
|
|
(void)d->sinit;
|
|
tc->sym->defaultval->accept(this);
|
|
}
|
|
d->type->accept(this);
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visitDeclaration(Declaration *decl)
|
|
{
|
|
if (decl->csym)
|
|
return;
|
|
if (SymbolDeclaration *sd = decl->isSymbolDeclaration())
|
|
{
|
|
sd->dsym->accept(this);
|
|
return;
|
|
}
|
|
if (TypeInfoDeclaration *tinfo = decl->isTypeInfoDeclaration())
|
|
{
|
|
tinfo->accept(this);
|
|
return;
|
|
}
|
|
if (FuncAliasDeclaration *fad = decl->isFuncAliasDeclaration())
|
|
return visitDeclaration(fad->funcalias);
|
|
if (decl->isField())
|
|
{
|
|
decl->toParent()->isAggregateDeclaration()->type->accept(this);
|
|
return;
|
|
}
|
|
if (FuncDeclaration *fd = decl->isFuncDeclaration())
|
|
{
|
|
if (!dmd::functionSemantic(fd))
|
|
return;
|
|
if (fd->needThis() && !fd->isMember2())
|
|
return;
|
|
(void)decl->ident->toChars();
|
|
fd->type->accept(this);
|
|
(void)fd->fbody;
|
|
(void)fd->hasDualContext();
|
|
AggregateDeclaration *ad = fd->isMember2();
|
|
(void)fd->isNested();
|
|
fd->isThis()->accept(this);
|
|
ad->handleType()->accept(this);
|
|
(void)fd->isVirtual();
|
|
(void)fd->vtblIndex;
|
|
if (fd->inlining == PINLINE::always || fd->inlining == PINLINE::never)
|
|
(void)fd->inlining;
|
|
if (fd->isCrtCtor() || fd->isCrtDtor())
|
|
(void)fd->flags;
|
|
(void)fd->isNaked();
|
|
(void)fd->isGenerated();
|
|
(void)fd->ident;
|
|
(void)fd->storage_class;
|
|
(void)fd->type->nextOf()->isTypeNoreturn();
|
|
}
|
|
else
|
|
{
|
|
VarDeclaration *vd = decl->isVarDeclaration();
|
|
(void)vd->isParameter();
|
|
(void)vd->canTakeAddressOf();
|
|
vd->type->accept(this);
|
|
(void)vd->alignment.isDefault();
|
|
(void)vd->alignment.get();
|
|
(void)vd->storage_class;
|
|
if (vd->storage_class & STCmanifest)
|
|
{
|
|
if (vd->_init && !vd->_init->isVoidInitializer())
|
|
{
|
|
Expression *ie = dmd::initializerToExpression(vd->_init);
|
|
ie->accept(this);
|
|
}
|
|
}
|
|
}
|
|
if (decl->isCodeseg() || decl->isDataseg())
|
|
{
|
|
if (decl->mangleOverride.length)
|
|
(void)decl->mangleOverride.ptr;
|
|
(void)decl->isInstantiated();
|
|
(void)decl->toPrettyChars(true);
|
|
}
|
|
if ((decl->storage_class & STCtemp) ||
|
|
(decl->storage_class & STCvolatile) ||
|
|
(decl->storage_class & STCdeprecated))
|
|
{
|
|
(void)decl->storage_class;
|
|
}
|
|
if (decl->visibility.kind == Visibility::private_ ||
|
|
decl->visibility.kind == Visibility::protected_)
|
|
{
|
|
(void)decl->visibility.kind;
|
|
}
|
|
(void)decl->isImportedSymbol();
|
|
(void)decl->isExport();
|
|
if (decl->isThreadlocal())
|
|
(void)decl->csym;
|
|
visitUserAttributes(decl);
|
|
}
|
|
void visit(VarDeclaration *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->type->ty == TY::Terror)
|
|
return;
|
|
if (d->type->isTypeNoreturn())
|
|
{
|
|
if (!d->isDataseg() && !d->isMember() &&
|
|
d->_init && !d->_init->isVoidInitializer())
|
|
{
|
|
Expression *e = d->type->defaultInitLiteral(d->loc);
|
|
e->accept(this);
|
|
}
|
|
return;
|
|
}
|
|
if (d->aliasTuple)
|
|
{
|
|
d->toAlias()->accept(this);
|
|
return;
|
|
}
|
|
if (!d->canTakeAddressOf())
|
|
{
|
|
if (!d->type->isScalar())
|
|
visitDeclaration(d);
|
|
}
|
|
else if (d->isDataseg() && !(d->storage_class & STCextern))
|
|
{
|
|
visitDeclaration(d);
|
|
dmd::size(d->type, d->loc);
|
|
if (d->_init)
|
|
{
|
|
if (!d->_init->isVoidInitializer())
|
|
{
|
|
Expression *e = dmd::initializerToExpression(d->_init, d->type);
|
|
e->accept(this);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Expression *e = d->type->defaultInitLiteral(d->loc);
|
|
e->accept(this);
|
|
}
|
|
}
|
|
else if (!d->isDataseg() && !d->isMember())
|
|
{
|
|
visitDeclaration(d);
|
|
if (d->_init && !d->_init->isVoidInitializer())
|
|
{
|
|
ExpInitializer *vinit = d->_init->isExpInitializer();
|
|
dmd::initializerToExpression(vinit)->accept(this);
|
|
if (d->needsScopeDtor())
|
|
d->edtor->accept(this);
|
|
}
|
|
}
|
|
d->type->accept(this);
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visit(TypeInfoDeclaration *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
visitDeclaration(d);
|
|
d->semanticRun = PASS::obj;
|
|
}
|
|
void visit(FuncDeclaration *d) override
|
|
{
|
|
if (d->semanticRun >= PASS::obj)
|
|
return;
|
|
if (d->isUnitTestDeclaration())
|
|
return;
|
|
if (TypeFunction *tf = d->type->isTypeFunction())
|
|
{
|
|
if (tf->next == NULL || tf->next->ty == TY::Terror)
|
|
return;
|
|
}
|
|
if (d->hasSemantic3Errors())
|
|
return;
|
|
if (d->isNested())
|
|
{
|
|
FuncDeclaration *fdp = d;
|
|
while (fdp && fdp->isNested())
|
|
{
|
|
fdp = fdp->toParent2()->isFuncDeclaration();
|
|
if (fdp == NULL)
|
|
break;
|
|
if (fdp->hasSemantic3Errors())
|
|
return;
|
|
}
|
|
}
|
|
if (d->semanticRun < PASS::semantic3)
|
|
{
|
|
dmd::functionSemantic3(d);
|
|
Module::runDeferredSemantic3();
|
|
}
|
|
if (global.errors)
|
|
return;
|
|
visitDeclaration(d);
|
|
if (!d->fbody)
|
|
return;
|
|
assert(d->semanticRun == PASS::semantic3done);
|
|
d->semanticRun = PASS::obj;
|
|
if (d->vthis)
|
|
visitDeclaration(d->vthis);
|
|
if (d->v_arguments)
|
|
visitDeclaration(d->v_arguments);
|
|
for (size_t i = 0; i < (d->parameters ? d->parameters->length : 0); i++)
|
|
{
|
|
VarDeclaration *param = (*d->parameters)[i];
|
|
visitDeclaration(param);
|
|
if (param->type->ty == TY::Tnoreturn)
|
|
break;
|
|
}
|
|
if (AggregateDeclaration *ad = d->isThis())
|
|
{
|
|
while (ad->isNested())
|
|
{
|
|
Dsymbol *pd = ad->toParent2();
|
|
visitDeclaration(ad->vthis);
|
|
ad = pd->isAggregateDeclaration();
|
|
if (ad == NULL)
|
|
break;
|
|
}
|
|
}
|
|
for (size_t i = 0; i < d->closureVars.length; i++)
|
|
{
|
|
VarDeclaration *v = d->closureVars[i];
|
|
if (!v->isParameter())
|
|
continue;
|
|
visitDeclaration(v);
|
|
}
|
|
if (d->vresult)
|
|
visitDeclaration(d->vresult);
|
|
if (d->isNRVO() && d->nrvo_var)
|
|
visitDeclaration(d->nrvo_var);
|
|
d->fbody->accept(this);
|
|
if (d->v_argptr)
|
|
visitDeclaration(d->v_argptr);
|
|
}
|
|
};
|
|
|
|
void test_backend(FuncDeclaration *f, Type *t)
|
|
{
|
|
MiniGlueVisitor v(f);
|
|
if (t->isNaked())
|
|
t->accept(&v);
|
|
else
|
|
{
|
|
Type *tb = dmd::castMod(t, 0);
|
|
tb->accept(&v);
|
|
(void)t->mod;
|
|
}
|
|
f->fbody->accept(&v);
|
|
}
|
|
|
|
void test_import_paths(const char *path, const char *imppath)
|
|
{
|
|
global.path.push(path);
|
|
global.params.imppath.shift(imppath);
|
|
}
|
|
|
|
/**********************************/
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
frontend_init();
|
|
|
|
test_tokens();
|
|
test_compiler_globals();
|
|
test_visitors();
|
|
test_semantic();
|
|
test_skip_importall();
|
|
test_expression();
|
|
test_target();
|
|
test_parameters();
|
|
test_types();
|
|
test_location();
|
|
test_array();
|
|
test_outbuffer();
|
|
test_cppmangle();
|
|
test_module();
|
|
test_optional();
|
|
test_filename();
|
|
|
|
frontend_term();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**********************************/
|
|
// Link Tests
|
|
|
|
void aggregate_h(StructDeclaration *sd)
|
|
{
|
|
dmd::search_toString(sd);
|
|
dmd::semanticTypeInfoMembers(sd);
|
|
}
|
|
|
|
void argtypes_h(Type *t)
|
|
{
|
|
// LLVM-only
|
|
//dmd::toArgTypes_x86(t);
|
|
//dmd::toArgTypes_sysv_x64(t);
|
|
//dmd::toArgTypes_aarch64(t);
|
|
//dmd::isHFVA(t);
|
|
}
|
|
|
|
void declaration_h(FuncDeclaration *fd, Loc loc, Expressions* args)
|
|
{
|
|
dmd::functionSemantic(fd);
|
|
dmd::functionSemantic3(fd);
|
|
::eval_builtin(loc, fd, args);
|
|
::isBuiltin(fd);
|
|
}
|
|
|
|
void doc_h(Module *m, const char *ptr, d_size_t length, const char *date,
|
|
ErrorSink *sink, OutBuffer &buf)
|
|
{
|
|
dmd::gendocfile(m, ptr, length, date, sink, buf);
|
|
}
|
|
|
|
void dsymbol_h(Dsymbol *d, Scope *sc, ScopeDsymbol *sds, Loc loc, Identifier *ident)
|
|
{
|
|
dmd::dsymbolSemantic(d, sc);
|
|
dmd::semantic2(d, sc);
|
|
dmd::semantic3(d, sc);
|
|
dmd::addMember(d, sc, sds);
|
|
dmd::search(d, loc, ident);
|
|
dmd::setScope(d, sc);
|
|
dmd::importAll(d, sc);
|
|
}
|
|
|
|
void expression_h(Expression *e, Scope *sc, Type *t, Loc loc, Expressions *es)
|
|
{
|
|
dmd::expressionSemantic(e, sc);
|
|
dmd::defaultInit(t, loc);
|
|
dmd::ctfeInterpret(e);
|
|
dmd::expandTuples(es);
|
|
dmd::optimize(e, 0);
|
|
}
|
|
|
|
void hdrgen_h(Module *m, OutBuffer &buf, Modules &ms, ParameterList pl,
|
|
Expression *e, Initializer *i, Statement *s, Type *t)
|
|
{
|
|
dmd::genhdrfile(m, true, buf);
|
|
dmd::genCppHdrFiles(ms);
|
|
dmd::moduleToBuffer(buf, true, m);
|
|
dmd::parametersTypeToChars(pl);
|
|
dmd::toChars(e);
|
|
dmd::toChars(i);
|
|
dmd::toChars(s);
|
|
dmd::toChars(t);
|
|
}
|
|
|
|
void init_h(Initializer *i, Type *t, Scope *sc, NeedInterpret ni)
|
|
{
|
|
dmd::initializerToExpression(i, t, true);
|
|
dmd::initializerSemantic(i, sc, t, ni);
|
|
}
|
|
|
|
void json_h(Modules &ms, OutBuffer &buf, const char *name)
|
|
{
|
|
dmd::json_generate(ms, buf);
|
|
dmd::tryParseJsonField(name);
|
|
}
|
|
|
|
void mangle_h(Dsymbol *s, FuncDeclaration *fd, Type *t, OutBuffer &buf,
|
|
Expression *e, TemplateInstance *ti)
|
|
{
|
|
dmd::toCppMangleItanium(s);
|
|
dmd::cppTypeInfoMangleItanium(s);
|
|
dmd::cppThunkMangleItanium(fd, 42);
|
|
dmd::mangleExact(fd);
|
|
dmd::mangleToBuffer(t, buf);
|
|
dmd::mangleToBuffer(e, buf);
|
|
dmd::mangleToBuffer(s, buf);
|
|
dmd::mangleToBuffer(ti, buf);
|
|
}
|
|
|
|
void module_h(Module *m, Array<ClassDeclaration* >& acs, ScopeDsymbol *sds)
|
|
{
|
|
dmd::getLocalClasses(m, acs);
|
|
dmd::findGetMembers(sds);
|
|
}
|
|
|
|
void mtype_h(Type *t1, Type *t2, Loc loc, Scope *sc, int *p)
|
|
{
|
|
dmd::typeSemantic(t1, loc, sc);
|
|
dmd::merge(t1);
|
|
dmd::isAggregate(t1);
|
|
dmd::hasPointers(t1);
|
|
dmd::toDsymbol(t1, sc);
|
|
dmd::equivalent(t1, t2);
|
|
dmd::covariant(t1, t2);
|
|
dmd::isBaseOf(t1, t2, p);
|
|
dmd::trySemantic(t1, loc, sc);
|
|
dmd::merge2(t1);
|
|
dmd::sarrayOf(t1, 0);
|
|
dmd::arrayOf(t1);
|
|
dmd::constOf(t1);
|
|
dmd::immutableOf(t1);
|
|
dmd::mutableOf(t1);
|
|
dmd::sharedOf(t1);
|
|
dmd::sharedConstOf(t1);
|
|
dmd::unSharedOf(t1);
|
|
dmd::wildOf(t1);
|
|
dmd::wildConstOf(t1);
|
|
dmd::sharedWildOf(t1);
|
|
dmd::sharedWildConstOf(t1);
|
|
dmd::castMod(t1, 0);
|
|
dmd::addMod(t1, 0);
|
|
dmd::pointerTo(t1);
|
|
dmd::referenceTo(t1);
|
|
}
|
|
|
|
void statement_h(Statement *s, AsmStatement *as, GccAsmStatement *gas,
|
|
CAsmDeclaration *ad, Scope *sc)
|
|
{
|
|
dmd::statementSemantic(s, sc);
|
|
dmd::asmSemantic(as, sc);
|
|
dmd::asmSemantic(ad, sc);
|
|
dmd::gccAsmSemantic(gas, sc);
|
|
dmd::gccAsmSemantic(ad, sc);
|
|
}
|
|
|
|
void template_h(TemplateParameter *tp, Scope *sc, TemplateParameters *tps,
|
|
RootObject *o, ErrorSink *sink)
|
|
{
|
|
dmd::tpsemantic(tp, sc, tps);
|
|
dmd::isExpression(o);
|
|
dmd::isDsymbol(o);
|
|
dmd::isType(o);
|
|
dmd::isTuple(o);
|
|
dmd::isParameter(o);
|
|
dmd::isTemplateParameter(o);
|
|
dmd::isError(o);
|
|
dmd::printTemplateStats(true, sink);
|
|
}
|
|
|
|
void typinf_h(Expression *e, Loc loc, Type *t, Scope *sc)
|
|
{
|
|
dmd::genTypeInfo(e, loc, t, sc);
|
|
::getTypeInfoType(loc, t, sc);
|
|
dmd::isSpeculativeType(t);
|
|
dmd::builtinTypeInfo(t);
|
|
}
|