/* Compiler implementation of the D programming language * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt */ #include "dsymbol.h" #include "aggregate.h" #include "attrib.h" #include "declaration.h" #include "errors.h" #include "import.h" #include "init.h" #include "module.h" #include "nspace.h" #include "objc.h" #include "scope.h" #include "staticassert.h" #include "template.h" #include "visitor.h" bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors); void udaExpressionEval(Scope *sc, Expressions *exps); Objc *objc(); class Semantic2Visitor : public Visitor { public: Scope *sc; Semantic2Visitor(Scope *sc) { this->sc = sc; } void visit(Dsymbol *) { // Most Dsymbols have no further semantic analysis needed } void visit(StaticAssert *sa) { //printf("StaticAssert::semantic2() %s\n", toChars()); ScopeDsymbol *sds = new ScopeDsymbol(); sc = sc->push(sds); sc->tinst = NULL; sc->minst = NULL; bool errors = false; bool result = evalStaticCondition(sc, sa->exp, sa->exp, errors); sc = sc->pop(); if (errors) { errorSupplemental(sa->loc, "while evaluating: static assert(%s)", sa->exp->toChars()); } else if (!result) { if (sa->msg) { sc = sc->startCTFE(); sa->msg = expressionSemantic(sa->msg, sc); sa->msg = resolveProperties(sc, sa->msg); sc = sc->endCTFE(); sa->msg = sa->msg->ctfeInterpret(); if (StringExp * se = sa->msg->toStringExp()) { // same with pragma(msg) se = se->toUTF8(sc); sa->error("\"%.*s\"", (int)se->len, (char *)se->string); } else sa->error("%s", sa->msg->toChars()); } else sa->error("(%s) is false", sa->exp->toChars()); if (sc->tinst) sc->tinst->printInstantiationTrace(); if (!global.gag) fatal(); } } void visit(TemplateInstance *tempinst) { if (tempinst->semanticRun >= PASSsemantic2) return; tempinst->semanticRun = PASSsemantic2; if (!tempinst->errors && tempinst->members) { TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration(); assert(tempdecl); sc = tempdecl->_scope; assert(sc); sc = sc->push(tempinst->argsym); sc = sc->push(tempinst); sc->tinst = tempinst; sc->minst = tempinst->minst; int needGagging = (tempinst->gagged && !global.gag); unsigned int olderrors = global.errors; int oldGaggedErrors = -1; // dead-store to prevent spurious warning if (needGagging) oldGaggedErrors = global.startGagging(); for (size_t i = 0; i < tempinst->members->length; i++) { Dsymbol *s = (*tempinst->members)[i]; semantic2(s, sc); if (tempinst->gagged && global.errors != olderrors) break; } if (global.errors != olderrors) { if (!tempinst->errors) { if (!tempdecl->literal) tempinst->error(tempinst->loc, "error instantiating"); if (tempinst->tinst) tempinst->tinst->printInstantiationTrace(); } tempinst->errors = true; } if (needGagging) global.endGagging(oldGaggedErrors); sc = sc->pop(); sc->pop(); } } void visit(TemplateMixin *tmix) { if (tmix->semanticRun >= PASSsemantic2) return; tmix->semanticRun = PASSsemantic2; if (tmix->members) { assert(sc); sc = sc->push(tmix->argsym); sc = sc->push(tmix); for (size_t i = 0; i < tmix->members->length; i++) { Dsymbol *s = (*tmix->members)[i]; semantic2(s, sc); } sc = sc->pop(); sc->pop(); } } void visit(VarDeclaration *vd) { if (vd->semanticRun < PASSsemanticdone && vd->inuse) return; //printf("VarDeclaration::semantic2('%s')\n", toChars()); if (vd->_init && !vd->toParent()->isFuncDeclaration()) { vd->inuse++; /* https://issues.dlang.org/show_bug.cgi?id=20280 * * Template instances may import modules that have not * finished semantic1. */ if (!vd->type) dsymbolSemantic(vd, sc); // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof vd->_init = initializerSemantic(vd->_init, sc, vd->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret); vd->inuse--; } if (vd->_init && (vd->storage_class & STCmanifest)) { /* Cannot initializer enums with CTFE classreferences and addresses of struct literals. * Scan initializer looking for them. Issue error if found. */ if (ExpInitializer *ei = vd->_init->isExpInitializer()) { struct EnumInitializer { static bool arrayHasInvalidEnumInitializer(Expressions *elems) { for (size_t i = 0; i < elems->length; i++) { Expression *e = (*elems)[i]; if (e && hasInvalidEnumInitializer(e)) return true; } return false; } static bool hasInvalidEnumInitializer(Expression *e) { if (e->op == TOKclassreference) return true; if (e->op == TOKaddress && ((AddrExp *)e)->e1->op == TOKstructliteral) return true; if (e->op == TOKarrayliteral) return arrayHasInvalidEnumInitializer(((ArrayLiteralExp *)e)->elements); if (e->op == TOKstructliteral) return arrayHasInvalidEnumInitializer(((StructLiteralExp *)e)->elements); if (e->op == TOKassocarrayliteral) { AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e; return arrayHasInvalidEnumInitializer(ae->values) || arrayHasInvalidEnumInitializer(ae->keys); } return false; } }; if (EnumInitializer::hasInvalidEnumInitializer(ei->exp)) vd->error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead."); } } else if (vd->_init && vd->isThreadlocal()) { if ((vd->type->ty == Tclass) && vd->type->isMutable() && !vd->type->isShared()) { ExpInitializer *ei = vd->_init->isExpInitializer(); if (ei && ei->exp->op == TOKclassreference) vd->error("is mutable. Only const or immutable class thread local variable are allowed, not %s", vd->type->toChars()); } else if (vd->type->ty == Tpointer && vd->type->nextOf()->ty == Tstruct && vd->type->nextOf()->isMutable() && !vd->type->nextOf()->isShared()) { ExpInitializer *ei = vd->_init->isExpInitializer(); if (ei && ei->exp->op == TOKaddress && ((AddrExp *)ei->exp)->e1->op == TOKstructliteral) { vd->error("is a pointer to mutable struct. Only pointers to const, immutable or shared struct thread local variable are allowed, not %s", vd->type->toChars()); } } } vd->semanticRun = PASSsemantic2done; } void visit(Module *mod) { //printf("Module::semantic2('%s'): parent = %p\n", toChars(), mod->parent); if (mod->semanticRun != PASSsemanticdone) // semantic() not completed yet - could be recursive call return; mod->semanticRun = PASSsemantic2; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope *sc = Scope::createGlobal(mod); // create root scope //printf("Module = %p\n", sc.scopesym); // Pass 2 semantic routines: do initializers and function bodies for (size_t i = 0; i < mod->members->length; i++) { Dsymbol *s = (*mod->members)[i]; semantic2(s, sc); } if (mod->userAttribDecl) { semantic2(mod->userAttribDecl, sc); } sc = sc->pop(); sc->pop(); mod->semanticRun = PASSsemantic2done; //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), mod->parent); } void visit(FuncDeclaration *fd) { if (fd->semanticRun >= PASSsemantic2done) return; if (fd->semanticRun < PASSsemanticdone && !fd->errors) { /* https://issues.dlang.org/show_bug.cgi?id=21614 * * Template instances may import modules that have not * finished semantic1. */ dsymbolSemantic(fd, sc); } assert(fd->semanticRun <= PASSsemantic2); fd->semanticRun = PASSsemantic2; objc()->setSelector(fd, sc); objc()->validateSelector(fd); if (fd->parent->isClassDeclaration()) { objc()->checkLinkage(fd); } if (!fd->type || fd->type->ty != Tfunction) return; TypeFunction *f = fd->type->toTypeFunction(); const size_t nparams = f->parameterList.length(); // semantic for parameters' UDAs for (size_t i = 0; i < nparams; i++) { Parameter *param = f->parameterList[i]; if (param && param->userAttribDecl) semantic2(param->userAttribDecl, sc); } } void visit(Import *i) { //printf("Import::semantic2('%s')\n", toChars()); if (i->mod) { semantic2(i->mod, NULL); if (i->mod->needmoduleinfo) { //printf("module5 %s because of %s\n", sc->_module->toChars(), i->mod->toChars()); if (sc) sc->_module->needmoduleinfo = 1; } } } void visit(Nspace *ns) { if (ns->semanticRun >= PASSsemantic2) return; ns->semanticRun = PASSsemantic2; if (ns->members) { assert(sc); sc = sc->push(ns); sc->linkage = LINKcpp; for (size_t i = 0; i < ns->members->length; i++) { Dsymbol *s = (*ns->members)[i]; semantic2(s, sc); } sc->pop(); } } void visit(AttribDeclaration *ad) { Dsymbols *d = ad->include(sc); if (d) { Scope *sc2 = ad->newScope(sc); for (size_t i = 0; i < d->length; i++) { Dsymbol *s = (*d)[i]; semantic2(s, sc2); } if (sc2 != sc) sc2->pop(); } } /** * Run the DeprecatedDeclaration's semantic2 phase then its members. * * The message set via a `DeprecatedDeclaration` can be either of: * - a string literal * - an enum * - a static immutable * So we need to call ctfe to resolve it. * Afterward forwards to the members' semantic2. */ void visit(DeprecatedDeclaration *dd) { dd->getMessage(); visit((AttribDeclaration *)dd); } void visit(AlignDeclaration *ad) { ad->getAlignment(sc); visit((AttribDeclaration *)ad); } void visit(UserAttributeDeclaration *uad) { if (uad->decl && uad->atts && uad->atts->length && uad->_scope) { uad->_scope = NULL; udaExpressionEval(sc, uad->atts); } visit((AttribDeclaration *)uad); } void visit(AggregateDeclaration *ad) { //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), ad->type->toChars(), ad->errors); if (!ad->members) return; if (ad->_scope) { ad->error("has forward references"); return; } Scope *sc2 = ad->newScope(sc); ad->determineSize(ad->loc); for (size_t i = 0; i < ad->members->length; i++) { Dsymbol *s = (*ad->members)[i]; //printf("\t[%d] %s\n", i, s->toChars()); semantic2(s, sc2); } sc2->pop(); } }; /************************************* * Does semantic analysis on initializers and members of aggregates. */ void semantic2(Dsymbol *dsym, Scope *sc) { Semantic2Visitor v(sc); dsym->accept(&v); }