/** * 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(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 src = DArray(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 src = DArray(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 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 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 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 *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 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 src = DArray(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 opt = Optional::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& 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); }