/* 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 "root/dsystem.h" #include "root/aav.h" #include "dsymbol.h" #include "aggregate.h" #include "aliasthis.h" #include "attrib.h" #include "cond.h" #include "declaration.h" #include "enum.h" #include "errors.h" #include "hdrgen.h" #include "id.h" #include "import.h" #include "init.h" #include "mars.h" #include "module.h" #include "nspace.h" #include "objc.h" #include "parse.h" #include "scope.h" #include "statement.h" #include "staticassert.h" #include "target.h" #include "template.h" #include "utf.h" #include "version.h" #include "visitor.h" bool allowsContractWithoutBody(FuncDeclaration *funcdecl); bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0); VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e); Initializer *inferType(Initializer *init, Scope *sc); void MODtoBuffer(OutBuffer *buf, MOD mod); bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0); bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps); bool symbolIsVisible(Scope *sc, Dsymbol *s); Objc *objc(); static unsigned setMangleOverride(Dsymbol *s, char *sym) { AttribDeclaration *ad = s->isAttribDeclaration(); if (ad) { Dsymbols *decls = ad->include(NULL); unsigned nestedCount = 0; if (decls && decls->length) for (size_t i = 0; i < decls->length; ++i) nestedCount += setMangleOverride((*decls)[i], sym); return nestedCount; } else if (s->isFuncDeclaration() || s->isVarDeclaration()) { s->isDeclaration()->mangleOverride = sym; return 1; } else return 0; } /********************************** * Decide if attributes for this function can be inferred from examining * the function body. * Returns: * true if can */ static bool canInferAttributes(FuncDeclaration *fd, Scope *sc) { if (!fd->fbody) return false; if (fd->isVirtualMethod()) return false; // since they may be overridden if (sc->func && /********** this is for backwards compatibility for the moment ********/ (!fd->isMember() || (sc->func->isSafeBypassingInference() && !fd->isInstantiated()))) return true; if (fd->isFuncLiteralDeclaration() || // externs are not possible with literals (fd->storage_class & STCinference) || // do attribute inference (fd->inferRetType && !fd->isCtorDeclaration())) return true; if (fd->isInstantiated()) { TemplateInstance *ti = fd->parent->isTemplateInstance(); if (ti == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == fd->ident) return true; } return false; } /***************************************** * Initialize for inferring the attributes of this function. */ static void initInferAttributes(FuncDeclaration *fd) { //printf("initInferAttributes() for %s\n", toPrettyChars()); TypeFunction *tf = fd->type->toTypeFunction(); if (tf->purity == PUREimpure) // purity not specified fd->flags |= FUNCFLAGpurityInprocess; if (tf->trust == TRUSTdefault) fd->flags |= FUNCFLAGsafetyInprocess; if (!tf->isnothrow) fd->flags |= FUNCFLAGnothrowInprocess; if (!tf->isnogc) fd->flags |= FUNCFLAGnogcInprocess; if (!fd->isVirtual() || fd->introducing) fd->flags |= FUNCFLAGreturnInprocess; // Initialize for inferring STCscope if (global.params.vsafe) fd->flags |= FUNCFLAGinferScope; } static void badObjectDotD(ClassDeclaration *cd) { cd->error("missing or corrupt object.d"); fatal(); } /* Bugzilla 12078, 12143 and 15733: * While resolving base classes and interfaces, a base may refer * the member of this derived class. In that time, if all bases of * this class can be determined, we can go forward the semantc process * beyond the Lancestorsdone. To do the recursive semantic analysis, * temporarily set and unset `_scope` around exp(). */ static Type *resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, Type *type) { if (!scx) { scx = sc->copy(); scx->setNoFree(); } cd->_scope = scx; Type *t = typeSemantic(type, cd->loc, sc); cd->_scope = NULL; return t; } static void resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, ClassDeclaration *sym) { if (!scx) { scx = sc->copy(); scx->setNoFree(); } cd->_scope = scx; dsymbolSemantic(sym, NULL); cd->_scope = NULL; } class DsymbolSemanticVisitor : public Visitor { public: Scope *sc; DsymbolSemanticVisitor(Scope *sc) { this->sc = sc; } void visit(Dsymbol *dsym) { dsym->error("%p has no semantic routine", dsym); } void visit(ScopeDsymbol *) { } void visit(Declaration *) { } void visit(AliasThis *dsym) { if (dsym->semanticRun != PASSinit) return; if (dsym->_scope) { sc = dsym->_scope; dsym->_scope = NULL; } if (!sc) return; dsym->semanticRun = PASSsemantic; Dsymbol *p = sc->parent->pastMixin(); AggregateDeclaration *ad = p->isAggregateDeclaration(); if (!ad) { error(dsym->loc, "alias this can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); return; } assert(ad->members); Dsymbol *s = ad->search(dsym->loc, dsym->ident); if (!s) { s = sc->search(dsym->loc, dsym->ident, NULL); if (s) error(dsym->loc, "%s is not a member of %s", s->toChars(), ad->toChars()); else error(dsym->loc, "undefined identifier %s", dsym->ident->toChars()); return; } else if (ad->aliasthis && s != ad->aliasthis) { error(dsym->loc, "there can be only one alias this"); return; } if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad) { AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym; assert(ad2->type == Type::terror); ad->aliasthis = ad2->aliasthis; return; } /* disable the alias this conversion so the implicit conversion check * doesn't use it. */ ad->aliasthis = NULL; Dsymbol *sx = s; if (sx->isAliasDeclaration()) sx = sx->toAlias(); Declaration *d = sx->isDeclaration(); if (d && !d->isTupleDeclaration()) { Type *t = d->type; assert(t); if (ad->type->implicitConvTo(t) > MATCHnomatch) { error(dsym->loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars()); } } ad->aliasthis = s; dsym->semanticRun = PASSsemanticdone; } void visit(AliasDeclaration *dsym) { if (dsym->semanticRun >= PASSsemanticdone) return; assert(dsym->semanticRun <= PASSsemantic); dsym->storage_class |= sc->stc & STCdeprecated; dsym->protection = sc->protection; dsym->userAttribDecl = sc->userAttribDecl; if (!sc->func && dsym->inNonRoot()) return; aliasSemantic(dsym, sc); } void visit(VarDeclaration *dsym) { //if (dsym->semanticRun > PASSinit) // return; //dsym->semanticRun = PASSsemantic; if (dsym->semanticRun >= PASSsemanticdone) return; Scope *scx = NULL; if (dsym->_scope) { sc = dsym->_scope; scx = sc; dsym->_scope = NULL; } if (!sc) return; dsym->semanticRun = PASSsemantic; /* Pick up storage classes from context, but except synchronized, * override, abstract, and final. */ dsym->storage_class |= (sc->stc & ~(STCsynchronized | STCoverride | STCabstract | STCfinal)); if (dsym->storage_class & STCextern && dsym->_init) dsym->error("extern symbols cannot have initializers"); dsym->userAttribDecl = sc->userAttribDecl; AggregateDeclaration *ad = dsym->isThis(); if (ad) dsym->storage_class |= ad->storage_class & STC_TYPECTOR; /* If auto type inference, do the inference */ int inferred = 0; if (!dsym->type) { dsym->inuse++; // Infering the type requires running semantic, // so mark the scope as ctfe if required bool needctfe = (dsym->storage_class & (STCmanifest | STCstatic)) != 0; if (needctfe) sc = sc->startCTFE(); //printf("inferring type for %s with init %s\n", dsym->toChars(), dsym->_init->toChars()); dsym->_init = inferType(dsym->_init, sc); dsym->type = initializerToExpression(dsym->_init)->type; if (needctfe) sc = sc->endCTFE(); dsym->inuse--; inferred = 1; /* This is a kludge to support the existing syntax for RAII * declarations. */ dsym->storage_class &= ~STCauto; dsym->originalType = dsym->type->syntaxCopy(); } else { if (!dsym->originalType) dsym->originalType = dsym->type->syntaxCopy(); /* Prefix function attributes of variable declaration can affect * its type: * pure nothrow void function() fp; * static assert(is(typeof(fp) == void function() pure nothrow)); */ Scope *sc2 = sc->push(); sc2->stc |= (dsym->storage_class & STC_FUNCATTR); dsym->inuse++; dsym->type = typeSemantic(dsym->type, dsym->loc, sc2); dsym->inuse--; sc2->pop(); } //printf(" semantic type = %s\n", dsym->type ? dsym->type->toChars() : "null"); if (dsym->type->ty == Terror) dsym->errors = true; dsym->type->checkDeprecated(dsym->loc, sc); dsym->linkage = sc->linkage; dsym->parent = sc->parent; //printf("this = %p, parent = %p, '%s'\n", dsym, dsym->parent, dsym->parent->toChars()); dsym->protection = sc->protection; /* If scope's alignment is the default, use the type's alignment, * otherwise the scope overrrides. */ dsym->alignment = sc->alignment(); if (dsym->alignment == STRUCTALIGN_DEFAULT) dsym->alignment = dsym->type->alignment(); // use type's alignment //printf("sc->stc = %x\n", sc->stc); //printf("storage_class = x%x\n", dsym->storage_class); if (global.params.vcomplex) dsym->type->checkComplexTransition(dsym->loc); // Calculate type size + safety checks if (sc->func && !sc->intypeof) { if ((dsym->storage_class & STCgshared) && !dsym->isMember()) { if (sc->func->setUnsafe()) dsym->error("__gshared not allowed in safe functions; use shared"); } } Dsymbol *parent = dsym->toParent(); Type *tb = dsym->type->toBasetype(); Type *tbn = tb->baseElemOf(); if (tb->ty == Tvoid && !(dsym->storage_class & STClazy)) { if (inferred) { dsym->error("type %s is inferred from initializer %s, and variables cannot be of type void", dsym->type->toChars(), dsym->_init->toChars()); } else dsym->error("variables cannot be of type void"); dsym->type = Type::terror; tb = dsym->type; } if (tb->ty == Tfunction) { dsym->error("cannot be declared to be a function"); dsym->type = Type::terror; tb = dsym->type; } if (tb->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tb; if (!ts->sym->members) { dsym->error("no definition of struct `%s`", ts->toChars()); // Explain why the definition is required when it's part of another type if (!dsym->type->isTypeStruct()) { // Prefer Loc of the dependant type Dsymbol *s = dsym->type->toDsymbol(sc); Loc loc = s ? s->loc : dsym->loc; errorSupplemental(loc, "required by type `%s`", dsym->type->toChars()); } // Flag variable as error to avoid invalid error messages due to unknown size dsym->type = Type::terror; } } if ((dsym->storage_class & STCauto) && !inferred) dsym->error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?"); if (tb->ty == Ttuple) { /* Instead, declare variables for each of the tuple elements * and add those. */ TypeTuple *tt = (TypeTuple *)tb; size_t nelems = Parameter::dim(tt->arguments); Expression *ie = (dsym->_init && !dsym->_init->isVoidInitializer()) ? initializerToExpression(dsym->_init) : NULL; if (ie) ie = expressionSemantic(ie, sc); if (nelems > 0 && ie) { Expressions *iexps = new Expressions(); iexps->push(ie); Expressions *exps = new Expressions(); for (size_t pos = 0; pos < iexps->length; pos++) { Lexpand1: Expression *e = (*iexps)[pos]; Parameter *arg = Parameter::getNth(tt->arguments, pos); arg->type = typeSemantic(arg->type, dsym->loc, sc); //printf("[%d] iexps->length = %d, ", pos, iexps->length); //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars()); //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars()); if (e != ie) { if (iexps->length > nelems) goto Lnomatch; if (e->type->implicitConvTo(arg->type)) continue; } if (e->op == TOKtuple) { TupleExp *te = (TupleExp *)e; if (iexps->length - 1 + te->exps->length > nelems) goto Lnomatch; iexps->remove(pos); iexps->insert(pos, te->exps); (*iexps)[pos] = Expression::combine(te->e0, (*iexps)[pos]); goto Lexpand1; } else if (isAliasThisTuple(e)) { VarDeclaration *v = copyToTemp(0, "__tup", e); dsymbolSemantic(v, sc); VarExp *ve = new VarExp(dsym->loc, v); ve->type = e->type; exps->setDim(1); (*exps)[0] = ve; expandAliasThisTuples(exps, 0); for (size_t u = 0; u < exps->length ; u++) { Lexpand2: Expression *ee = (*exps)[u]; arg = Parameter::getNth(tt->arguments, pos + u); arg->type = typeSemantic(arg->type, dsym->loc, sc); //printf("[%d+%d] exps->length = %d, ", pos, u, exps->length); //printf("ee = (%s %s, %s), ", Token::tochars[ee->op], ee->toChars(), ee->type->toChars()); //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars()); size_t iexps_dim = iexps->length - 1 + exps->length; if (iexps_dim > nelems) goto Lnomatch; if (ee->type->implicitConvTo(arg->type)) continue; if (expandAliasThisTuples(exps, u) != -1) goto Lexpand2; } if ((*exps)[0] != ve) { Expression *e0 = (*exps)[0]; (*exps)[0] = new CommaExp(dsym->loc, new DeclarationExp(dsym->loc, v), e0); (*exps)[0]->type = e0->type; iexps->remove(pos); iexps->insert(pos, exps); goto Lexpand1; } } } if (iexps->length < nelems) goto Lnomatch; ie = new TupleExp(dsym->_init->loc, iexps); } Lnomatch: if (ie && ie->op == TOKtuple) { TupleExp *te = (TupleExp *)ie; size_t tedim = te->exps->length; if (tedim != nelems) { error(dsym->loc, "tuple of %d elements cannot be assigned to tuple of %d elements", (int)tedim, (int)nelems); for (size_t u = tedim; u < nelems; u++) // fill dummy expression te->exps->push(new ErrorExp()); } } Objects *exps = new Objects(); exps->setDim(nelems); for (size_t i = 0; i < nelems; i++) { Parameter *arg = Parameter::getNth(tt->arguments, i); OutBuffer buf; buf.printf("__%s_field_%llu", dsym->ident->toChars(), (ulonglong)i); const char *name = buf.extractChars(); Identifier *id = Identifier::idPool(name); Initializer *ti; if (ie) { Expression *einit = ie; if (ie->op == TOKtuple) { TupleExp *te = (TupleExp *)ie; einit = (*te->exps)[i]; if (i == 0) einit = Expression::combine(te->e0, einit); } ti = new ExpInitializer(einit->loc, einit); } else ti = dsym->_init ? dsym->_init->syntaxCopy() : NULL; VarDeclaration *v = new VarDeclaration(dsym->loc, arg->type, id, ti); v->storage_class |= STCtemp | STClocal | dsym->storage_class; if (arg->storageClass & STCparameter) v->storage_class |= arg->storageClass; //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); dsymbolSemantic(v, sc); if (sc->scopesym) { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); if (sc->scopesym->members) sc->scopesym->members->push(v); } Expression *e = new DsymbolExp(dsym->loc, v); (*exps)[i] = e; } TupleDeclaration *v2 = new TupleDeclaration(dsym->loc, dsym->ident, exps); v2->parent = dsym->parent; v2->isexp = true; dsym->aliassym = v2; dsym->semanticRun = PASSsemanticdone; return; } /* Storage class can modify the type */ dsym->type = dsym->type->addStorageClass(dsym->storage_class); /* Adjust storage class to reflect type */ if (dsym->type->isConst()) { dsym->storage_class |= STCconst; if (dsym->type->isShared()) dsym->storage_class |= STCshared; } else if (dsym->type->isImmutable()) dsym->storage_class |= STCimmutable; else if (dsym->type->isShared()) dsym->storage_class |= STCshared; else if (dsym->type->isWild()) dsym->storage_class |= STCwild; if (StorageClass stc = dsym->storage_class & (STCsynchronized | STCoverride | STCabstract | STCfinal)) { if (stc == STCfinal) dsym->error("cannot be final, perhaps you meant const?"); else { OutBuffer buf; stcToBuffer(&buf, stc); dsym->error("cannot be %s", buf.peekChars()); } dsym->storage_class &= ~stc; // strip off } if (dsym->storage_class & STCscope) { StorageClass stc = dsym->storage_class & (STCstatic | STCextern | STCmanifest | STCtls | STCgshared); if (stc) { OutBuffer buf; stcToBuffer(&buf, stc); dsym->error("cannot be `scope` and `%s`", buf.peekChars()); } else if (dsym->isMember()) { dsym->error("field cannot be `scope`"); } else if (!dsym->type->hasPointers()) { dsym->storage_class &= ~STCscope; // silently ignore; may occur in generic code } } if (dsym->storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe)) { } else { AggregateDeclaration *aad = parent->isAggregateDeclaration(); if (aad) { if (global.params.vfield && dsym->storage_class & (STCconst | STCimmutable) && dsym->_init && !dsym->_init->isVoidInitializer()) { const char *s = (dsym->storage_class & STCimmutable) ? "immutable" : "const"; message(dsym->loc, "`%s.%s` is `%s` field", ad->toPrettyChars(), dsym->toChars(), s); } dsym->storage_class |= STCfield; if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor) { if (!dsym->isThisDeclaration() && !dsym->_init) aad->noDefaultCtor = true; } } InterfaceDeclaration *id = parent->isInterfaceDeclaration(); if (id) { dsym->error("field not allowed in interface"); } else if (aad && aad->sizeok == SIZEOKdone) { dsym->error("cannot be further field because it will change the determined %s size", aad->toChars()); } /* Templates cannot add fields to aggregates */ TemplateInstance *ti = parent->isTemplateInstance(); if (ti) { // Take care of nested templates while (1) { TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); if (!ti2) break; ti = ti2; } // If it's a member template AggregateDeclaration *ad2 = ti->tempdecl->isMember(); if (ad2 && dsym->storage_class != STCundefined) { dsym->error("cannot use template to add field to aggregate `%s`", ad2->toChars()); } } } if ((dsym->storage_class & (STCref | STCparameter | STCforeach | STCtemp | STCresult)) == STCref && dsym->ident != Id::This) { dsym->error("only parameters or foreach declarations can be ref"); } if (dsym->type->hasWild()) { if (dsym->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) || dsym->isDataseg() ) { dsym->error("only parameters or stack based variables can be inout"); } FuncDeclaration *func = sc->func; if (func) { if (func->fes) func = func->fes->func; bool isWild = false; for (FuncDeclaration *fd = func; fd; fd = fd->toParent2()->isFuncDeclaration()) { if (((TypeFunction *)fd->type)->iswild) { isWild = true; break; } } if (!isWild) { dsym->error("inout variables can only be declared inside inout functions"); } } } if (!(dsym->storage_class & (STCctfe | STCref | STCresult)) && tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor) { if (!dsym->_init) { if (dsym->isField()) { /* For fields, we'll check the constructor later to make sure it is initialized */ dsym->storage_class |= STCnodefaultctor; } else if (dsym->storage_class & STCparameter) ; else dsym->error("default construction is disabled for type %s", dsym->type->toChars()); } } FuncDeclaration *fd = parent->isFuncDeclaration(); if (dsym->type->isscope() && !(dsym->storage_class & STCnodtor)) { if (dsym->storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd) { dsym->error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope"); } if (!(dsym->storage_class & STCscope)) { if (!(dsym->storage_class & STCparameter) && dsym->ident != Id::withSym) dsym->error("reference to scope class must be scope"); } } // Calculate type size + safety checks if (sc->func && !sc->intypeof) { if (dsym->_init && dsym->_init->isVoidInitializer() && dsym->type->hasPointers()) // get type size { if (sc->func->setUnsafe()) dsym->error("void initializers for pointers not allowed in safe functions"); } else if (!dsym->_init && !(dsym->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield | STCparameter)) && dsym->type->hasVoidInitPointers()) { if (sc->func->setUnsafe()) dsym->error("void initializers for pointers not allowed in safe functions"); } } if (!dsym->_init && !fd) { // If not mutable, initializable by constructor only dsym->storage_class |= STCctorinit; } if (dsym->_init) dsym->storage_class |= STCinit; // remember we had an explicit initializer else if (dsym->storage_class & STCmanifest) dsym->error("manifest constants must have initializers"); bool isBlit = false; d_uns64 sz = 0; if (!dsym->_init && !sc->inunion && !(dsym->storage_class & (STCstatic | STCgshared | STCextern)) && fd && (!(dsym->storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult)) || (dsym->storage_class & STCout)) && (sz = dsym->type->size()) != 0) { // Provide a default initializer //printf("Providing default initializer for '%s'\n", dsym->toChars()); if (sz == SIZE_INVALID && dsym->type->ty != Terror) dsym->error("size of type %s is invalid", dsym->type->toChars()); Type *tv = dsym->type; while (tv->ty == Tsarray) // Don't skip Tenum tv = tv->nextOf(); if (tv->needsNested()) { /* Nested struct requires valid enclosing frame pointer. * In StructLiteralExp::toElem(), it's calculated. */ assert(tv->toBasetype()->ty == Tstruct); checkFrameAccess(dsym->loc, sc, ((TypeStruct *)tbn)->sym); Expression *e = tv->defaultInitLiteral(dsym->loc); e = new BlitExp(dsym->loc, new VarExp(dsym->loc, dsym), e); e = expressionSemantic(e, sc); dsym->_init = new ExpInitializer(dsym->loc, e); goto Ldtor; } if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->zeroInit == 1) { /* If a struct is all zeros, as a special case * set it's initializer to the integer 0. * In AssignExp::toElem(), we check for this and issue * a memset() to initialize the struct. * Must do same check in interpreter. */ Expression *e = new IntegerExp(dsym->loc, 0, Type::tint32); e = new BlitExp(dsym->loc, new VarExp(dsym->loc, dsym), e); e->type = dsym->type; // don't type check this, it would fail dsym->_init = new ExpInitializer(dsym->loc, e); goto Ldtor; } if (dsym->type->baseElemOf()->ty == Tvoid) { dsym->error("%s does not have a default initializer", dsym->type->toChars()); } else if (Expression *e = dsym->type->defaultInit(dsym->loc)) { dsym->_init = new ExpInitializer(dsym->loc, e); } // Default initializer is always a blit isBlit = true; } if (dsym->_init) { sc = sc->push(); sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCnogc | STCref | STCdisable); ExpInitializer *ei = dsym->_init->isExpInitializer(); if (ei) // Bugzilla 13424: Preset the required type to fail in FuncLiteralDeclaration::semantic3 ei->exp = inferType(ei->exp, dsym->type); // If inside function, there is no semantic3() call if (sc->func || sc->intypeof == 1) { // If local variable, use AssignExp to handle all the various // possibilities. if (fd && !(dsym->storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) && !dsym->_init->isVoidInitializer()) { //printf("fd = '%s', var = '%s'\n", fd->toChars(), dsym->toChars()); if (!ei) { ArrayInitializer *ai = dsym->_init->isArrayInitializer(); Expression *e; if (ai && tb->ty == Taarray) e = ai->toAssocArrayLiteral(); else e = initializerToExpression(dsym->_init); if (!e) { // Run semantic, but don't need to interpret dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, INITnointerpret); e = initializerToExpression(dsym->_init); if (!e) { dsym->error("is not a static and cannot have static initializer"); e = new ErrorExp(); } } ei = new ExpInitializer(dsym->_init->loc, e); dsym->_init = ei; } Expression *exp = ei->exp; Expression *e1 = new VarExp(dsym->loc, dsym); if (isBlit) exp = new BlitExp(dsym->loc, e1, exp); else exp = new ConstructExp(dsym->loc, e1, exp); dsym->canassign++; exp = expressionSemantic(exp, sc); dsym->canassign--; exp = exp->optimize(WANTvalue); if (exp->op == TOKerror) { dsym->_init = new ErrorInitializer(); ei = NULL; } else ei->exp = exp; if (ei && dsym->isScope()) { Expression *ex = ei->exp; while (ex->op == TOKcomma) ex = ((CommaExp *)ex)->e2; if (ex->op == TOKblit || ex->op == TOKconstruct) ex = ((AssignExp *)ex)->e2; if (ex->op == TOKnew) { // See if initializer is a NewExp that can be allocated on the stack NewExp *ne = (NewExp *)ex; if (dsym->type->toBasetype()->ty == Tclass) { if (ne->newargs && ne->newargs->length > 1) { dsym->mynew = true; } else { ne->onstack = true; dsym->onstack = true; } } } else if (ex->op == TOKfunction) { // or a delegate that doesn't escape a reference to the function FuncDeclaration *f = ((FuncExp *)ex)->fd; f->tookAddressOf--; } } } else { // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret); } } else if (parent->isAggregateDeclaration()) { dsym->_scope = scx ? scx : sc->copy(); dsym->_scope->setNoFree(); } else if (dsym->storage_class & (STCconst | STCimmutable | STCmanifest) || dsym->type->isConst() || dsym->type->isImmutable()) { /* Because we may need the results of a const declaration in a * subsequent type, such as an array dimension, before semantic2() * gets ordinarily run, try to run semantic2() now. * Ignore failure. */ if (!inferred) { unsigned errors = global.errors; dsym->inuse++; if (ei) { Expression *exp = ei->exp->syntaxCopy(); bool needctfe = dsym->isDataseg() || (dsym->storage_class & STCmanifest); if (needctfe) sc = sc->startCTFE(); exp = expressionSemantic(exp, sc); exp = resolveProperties(sc, exp); if (needctfe) sc = sc->endCTFE(); Type *tb2 = dsym->type->toBasetype(); Type *ti = exp->type->toBasetype(); /* The problem is the following code: * struct CopyTest { * double x; * this(double a) { x = a * 10.0;} * this(this) { x += 2.0; } * } * const CopyTest z = CopyTest(5.3); // ok * const CopyTest w = z; // not ok, postblit not run * static assert(w.x == 55.0); * because the postblit doesn't get run on the initialization of w. */ if (ti->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)ti)->sym; /* Look to see if initializer involves a copy constructor * (which implies a postblit) */ // there is a copy constructor // and exp is the same struct if (sd->postblit && tb2->toDsymbol(NULL) == sd) { // The only allowable initializer is a (non-copy) constructor if (exp->isLvalue()) dsym->error("of type struct %s uses this(this), which is not allowed in static initialization", tb2->toChars()); } } ei->exp = exp; } dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, INITinterpret); dsym->inuse--; if (global.errors > errors) { dsym->_init = new ErrorInitializer(); dsym->type = Type::terror; } } else { dsym->_scope = scx ? scx : sc->copy(); dsym->_scope->setNoFree(); } } sc = sc->pop(); } Ldtor: /* Build code to execute destruction, if necessary */ dsym->edtor = dsym->callScopeDtor(sc); if (dsym->edtor) { if (sc->func && dsym->storage_class & (STCstatic | STCgshared)) dsym->edtor = expressionSemantic(dsym->edtor, sc->_module->_scope); else dsym->edtor = expressionSemantic(dsym->edtor, sc); #if 0 // currently disabled because of std.stdio.stdin, stdout and stderr if (dsym->isDataseg() && !(dsym->storage_class & STCextern)) dsym->error("static storage variables cannot have destructors"); #endif } dsym->semanticRun = PASSsemanticdone; if (dsym->type->toBasetype()->ty == Terror) dsym->errors = true; if (sc->scopesym && !sc->scopesym->isAggregateDeclaration()) { for (ScopeDsymbol *sym = sc->scopesym; sym && dsym->endlinnum == 0; sym = sym->parent ? sym->parent->isScopeDsymbol() : NULL) dsym->endlinnum = sym->endlinnum; } } void visit(TypeInfoDeclaration *dsym) { assert(dsym->linkage == LINKc); } void visit(Import *imp) { //printf("Import::semantic('%s') %s\n", toPrettyChars(), imp->id->toChars()); if (imp->semanticRun > PASSinit) return; if (imp->_scope) { sc = imp->_scope; imp->_scope = NULL; } if (!sc) return; imp->semanticRun = PASSsemantic; // Load if not already done so if (!imp->mod) { imp->load(sc); if (imp->mod) imp->mod->importAll(NULL); } if (imp->mod) { // Modules need a list of each imported module //printf("%s imports %s\n", sc->_module->toChars(), imp->mod->toChars()); sc->_module->aimports.push(imp->mod); if (sc->explicitProtection) imp->protection = sc->protection; if (!imp->aliasId && !imp->names.length) // neither a selective nor a renamed import { ScopeDsymbol *scopesym = NULL; if (sc->explicitProtection) imp->protection = sc->protection.kind; for (Scope *scd = sc; scd; scd = scd->enclosing) { if (!scd->scopesym) continue; scopesym = scd->scopesym; break; } if (!imp->isstatic) { scopesym->importScope(imp->mod, imp->protection); } imp->addPackageAccess(scopesym); } dsymbolSemantic(imp->mod, NULL); if (imp->mod->needmoduleinfo) { //printf("module4 %s because of %s\n", sc->_module->toChars(), imp->mod->toChars()); sc->_module->needmoduleinfo = 1; } sc = sc->push(imp->mod); sc->protection = imp->protection; for (size_t i = 0; i < imp->aliasdecls.length; i++) { AliasDeclaration *ad = imp->aliasdecls[i]; //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), imp->aliases[i]->toChars(), imp->names[i]->toChars(), ad->_scope); Dsymbol *sym = imp->mod->search(imp->loc, imp->names[i], IgnorePrivateImports); if (sym) { if (!symbolIsVisible(sc, sym)) imp->mod->error(imp->loc, "member `%s` is not visible from module `%s`", imp->names[i]->toChars(), sc->_module->toChars()); dsymbolSemantic(ad, sc); // If the import declaration is in non-root module, // analysis of the aliased symbol is deferred. // Therefore, don't see the ad->aliassym or ad->type here. } else { Dsymbol *s = imp->mod->search_correct(imp->names[i]); if (s) imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toPrettyChars()); else imp->mod->error(imp->loc, "import `%s` not found", imp->names[i]->toChars()); ad->type = Type::terror; } } sc = sc->pop(); } imp->semanticRun = PASSsemanticdone; // object self-imports itself, so skip that (Bugzilla 7547) // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164) if (global.params.moduleDeps != NULL && !(imp->id == Id::object && sc->_module->ident == Id::object) && sc->_module->ident != Id::entrypoint && strcmp(sc->_module->ident->toChars(), "__main") != 0) { /* The grammar of the file is: * ImportDeclaration * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " * ModuleAliasIdentifier ] "\n" * * BasicImportDeclaration * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string" * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" * * FilePath * - any string with '(', ')' and '\' escaped with the '\' character */ OutBuffer *ob = global.params.moduleDeps; Module* imod = sc->instantiatingModule(); if (!global.params.moduleDepsFile.length) ob->writestring("depsImport "); ob->writestring(imod->toPrettyChars()); ob->writestring(" ("); escapePath(ob, imod->srcfile->toChars()); ob->writestring(") : "); // use protection instead of sc->protection because it couldn't be // resolved yet, see the comment above protectionToBuffer(ob, imp->protection); ob->writeByte(' '); if (imp->isstatic) { stcToBuffer(ob, STCstatic); ob->writeByte(' '); } ob->writestring(": "); if (imp->packages) { for (size_t i = 0; i < imp->packages->length; i++) { Identifier *pid = (*imp->packages)[i]; ob->printf("%s.", pid->toChars()); } } ob->writestring(imp->id->toChars()); ob->writestring(" ("); if (imp->mod) escapePath(ob, imp->mod->srcfile->toChars()); else ob->writestring("???"); ob->writeByte(')'); for (size_t i = 0; i < imp->names.length; i++) { if (i == 0) ob->writeByte(':'); else ob->writeByte(','); Identifier *name = imp->names[i]; Identifier *alias = imp->aliases[i]; if (!alias) { ob->printf("%s", name->toChars()); alias = name; } else ob->printf("%s=%s", alias->toChars(), name->toChars()); } if (imp->aliasId) ob->printf(" -> %s", imp->aliasId->toChars()); ob->writenl(); } //printf("-Import::semantic('%s'), pkg = %p\n", imp->toChars(), imp->pkg); } void attribSemantic(AttribDeclaration *ad) { if (ad->semanticRun != PASSinit) return; ad->semanticRun = PASSsemantic; Dsymbols *d = ad->include(sc); //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); if (d) { Scope *sc2 = ad->newScope(sc); bool errors = false; for (size_t i = 0; i < d->length; i++) { Dsymbol *s = (*d)[i]; dsymbolSemantic(s, sc2); errors |= s->errors; } ad->errors |= errors; if (sc2 != sc) sc2->pop(); } ad->semanticRun = PASSsemanticdone; } void visit(AttribDeclaration *atd) { attribSemantic(atd); } void visit(AnonDeclaration *scd) { //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", scd); assert(sc->parent); Dsymbol *p = sc->parent->pastMixin(); AggregateDeclaration *ad = p->isAggregateDeclaration(); if (!ad) { error(scd->loc, "%s can only be a part of an aggregate, not %s %s", scd->kind(), p->kind(), p->toChars()); scd->errors = true; return; } if (scd->decl) { sc = sc->push(); sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); sc->inunion = scd->isunion; sc->flags = 0; for (size_t i = 0; i < scd->decl->length; i++) { Dsymbol *s = (*scd->decl)[i]; dsymbolSemantic(s, sc); } sc = sc->pop(); } } void visit(PragmaDeclaration *pd) { // Should be merged with PragmaStatement //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); if (pd->ident == Id::msg) { if (pd->args) { for (size_t i = 0; i < pd->args->length; i++) { Expression *e = (*pd->args)[i]; sc = sc->startCTFE(); e = expressionSemantic(e, sc); e = resolveProperties(sc, e); sc = sc->endCTFE(); e = ctfeInterpretForPragmaMsg(e); if (e->op == TOKerror) { errorSupplemental(pd->loc, "while evaluating pragma(msg, %s)", (*pd->args)[i]->toChars()); return; } StringExp *se = e->toStringExp(); if (se) { se = se->toUTF8(sc); fprintf(stderr, "%.*s", (int)se->len, (char *)se->string); } else fprintf(stderr, "%s", e->toChars()); } fprintf(stderr, "\n"); } goto Lnodecl; } else if (pd->ident == Id::lib) { if (!pd->args || pd->args->length != 1) pd->error("string expected for library name"); else { StringExp *se = semanticString(sc, (*pd->args)[0], "library name"); if (!se) goto Lnodecl; (*pd->args)[0] = se; char *name = (char *)mem.xmalloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; if (global.params.verbose) message("library %s", name); if (global.params.moduleDeps && !global.params.moduleDepsFile.length) { OutBuffer *ob = global.params.moduleDeps; Module *imod = sc->instantiatingModule(); ob->writestring("depsLib "); ob->writestring(imod->toPrettyChars()); ob->writestring(" ("); escapePath(ob, imod->srcfile->toChars()); ob->writestring(") : "); ob->writestring((char *) name); ob->writenl(); } mem.xfree(name); } goto Lnodecl; } else if (pd->ident == Id::startaddress) { if (!pd->args || pd->args->length != 1) pd->error("function name expected for start address"); else { /* Bugzilla 11980: * resolveProperties and ctfeInterpret call are not necessary. */ Expression *e = (*pd->args)[0]; sc = sc->startCTFE(); e = expressionSemantic(e, sc); sc = sc->endCTFE(); (*pd->args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) pd->error("function name expected for start address, not `%s`", e->toChars()); } goto Lnodecl; } else if (pd->ident == Id::Pinline) { goto Ldecl; } else if (pd->ident == Id::mangle) { if (!pd->args) pd->args = new Expressions(); if (pd->args->length != 1) { pd->error("string expected for mangled name"); pd->args->setDim(1); (*pd->args)[0] = new ErrorExp(); // error recovery goto Ldecl; } StringExp *se = semanticString(sc, (*pd->args)[0], "mangled name"); if (!se) goto Ldecl; (*pd->args)[0] = se; // Will be used for later if (!se->len) { pd->error("zero-length string not allowed for mangled name"); goto Ldecl; } if (se->sz != 1) { pd->error("mangled name characters can only be of type char"); goto Ldecl; } /* Note: D language specification should not have any assumption about backend * implementation. Ideally pragma(mangle) can accept a string of any content. * * Therefore, this validation is compiler implementation specific. */ for (size_t i = 0; i < se->len; ) { utf8_t *p = (utf8_t *)se->string; dchar_t c = p[i]; if (c < 0x80) { if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c != 0 && strchr("$%().:?@[]_", c))) { ++i; continue; } else { pd->error("char 0x%02x not allowed in mangled name", c); break; } } if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c)) { pd->error("%s", msg); break; } if (!isUniAlpha(c)) { pd->error("char 0x%04x not allowed in mangled name", c); break; } } } else if (pd->ident == Id::printf || pd->ident == Id::scanf) { if (pd->args && pd->args->length != 0) pd->error("takes no argument"); goto Ldecl; } else if (global.params.ignoreUnsupportedPragmas) { if (global.params.verbose) { /* Print unrecognized pragmas */ OutBuffer buf; buf.writestring(pd->ident->toChars()); if (pd->args) { for (size_t i = 0; i < pd->args->length; i++) { Expression *e = (*pd->args)[i]; sc = sc->startCTFE(); e = expressionSemantic(e, sc); e = resolveProperties(sc, e); sc = sc->endCTFE(); e = e->ctfeInterpret(); if (i == 0) buf.writestring(" ("); else buf.writeByte(','); buf.writestring(e->toChars()); } if (pd->args->length) buf.writeByte(')'); } message("pragma %s", buf.peekChars()); } goto Lnodecl; } else error(pd->loc, "unrecognized pragma(%s)", pd->ident->toChars()); Ldecl: if (pd->decl) { Scope *sc2 = pd->newScope(sc); for (size_t i = 0; i < pd->decl->length; i++) { Dsymbol *s = (*pd->decl)[i]; dsymbolSemantic(s, sc2); if (pd->ident == Id::mangle) { assert(pd->args && pd->args->length == 1); if (StringExp *se = (*pd->args)[0]->toStringExp()) { char *name = (char *)mem.xmalloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; unsigned cnt = setMangleOverride(s, name); if (cnt > 1) pd->error("can only apply to a single declaration"); } } } if (sc2 != sc) sc2->pop(); } return; Lnodecl: if (pd->decl) { pd->error("pragma is missing closing `;`"); goto Ldecl; // do them anyway, to avoid segfaults. } } void visit(StaticIfDeclaration *sid) { attribSemantic(sid); } void visit(StaticForeachDeclaration *sfd) { attribSemantic(sfd); } Dsymbols *compileIt(CompileDeclaration *cd) { //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd->loc.linnum, cd->exp->toChars()); OutBuffer buf; if (expressionsToString(buf, sc, cd->exps)) return NULL; unsigned errors = global.errors; const size_t len = buf.length(); const char *str = buf.extractChars(); Parser p(cd->loc, sc->_module, (const utf8_t *)str, len, false); p.nextToken(); Dsymbols *d = p.parseDeclDefs(0); if (global.errors != errors) return NULL; if (p.token.value != TOKeof) { cd->error("incomplete mixin declaration (%s)", str); return NULL; } return d; } void visit(CompileDeclaration *cd) { //printf("CompileDeclaration::semantic()\n"); if (!cd->compiled) { cd->decl = compileIt(cd); cd->AttribDeclaration::addMember(sc, cd->scopesym); cd->compiled = true; if (cd->_scope && cd->decl) { for (size_t i = 0; i < cd->decl->length; i++) { Dsymbol *s = (*cd->decl)[i]; s->setScope(cd->_scope); } } } attribSemantic(cd); } void visit(UserAttributeDeclaration *uad) { //printf("UserAttributeDeclaration::semantic() %p\n", this); if (uad->decl && !uad->_scope) uad->Dsymbol::setScope(sc); // for function local symbols attribSemantic(uad); } void visit(StaticAssert *sa) { if (sa->semanticRun < PASSsemanticdone) sa->semanticRun = PASSsemanticdone; } void visit(DebugSymbol *ds) { //printf("DebugSymbol::semantic() %s\n", ds->toChars()); if (ds->semanticRun < PASSsemanticdone) ds->semanticRun = PASSsemanticdone; } void visit(VersionSymbol *vs) { if (vs->semanticRun < PASSsemanticdone) vs->semanticRun = PASSsemanticdone; } void visit(Package *pkg) { if (pkg->semanticRun < PASSsemanticdone) pkg->semanticRun = PASSsemanticdone; } void visit(Module *m) { if (m->semanticRun != PASSinit) return; //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, m->toChars(), parent); m->semanticRun = PASSsemantic; // 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 = m->_scope; // see if already got one from importAll() if (!sc) { sc = Scope::createGlobal(m); // create root scope } //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); // Pass 1 semantic routines: do public side of the definition for (size_t i = 0; i < m->members->length; i++) { Dsymbol *s = (*m->members)[i]; //printf("\tModule('%s'): '%s'.semantic()\n", m->toChars(), s->toChars()); dsymbolSemantic(s, sc); m->runDeferredSemantic(); } if (m->userAttribDecl) { dsymbolSemantic(m->userAttribDecl, sc); } if (!m->_scope) { sc = sc->pop(); sc->pop(); // 2 pops because Scope::createGlobal() created 2 } m->semanticRun = PASSsemanticdone; //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", m, m->toChars(), parent); } void visit(EnumDeclaration *ed) { //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), ed->toChars()); //printf("EnumDeclaration::semantic() %p %s\n", ed, ed->toChars()); if (ed->semanticRun >= PASSsemanticdone) return; // semantic() already completed if (ed->semanticRun == PASSsemantic) { assert(ed->memtype); error(ed->loc, "circular reference to enum base type %s", ed->memtype->toChars()); ed->errors = true; ed->semanticRun = PASSsemanticdone; return; } unsigned dprogress_save = Module::dprogress; Scope *scx = NULL; if (ed->_scope) { sc = ed->_scope; scx = ed->_scope; // save so we don't make redundant copies ed->_scope = NULL; } if (!sc) return; ed->parent = sc->parent; ed->type = typeSemantic(ed->type, ed->loc, sc); ed->protection = sc->protection; if (sc->stc & STCdeprecated) ed->isdeprecated = true; ed->userAttribDecl = sc->userAttribDecl; ed->semanticRun = PASSsemantic; if (!ed->members && !ed->memtype) // enum ident; { ed->semanticRun = PASSsemanticdone; return; } if (!ed->symtab) ed->symtab = new DsymbolTable(); /* The separate, and distinct, cases are: * 1. enum { ... } * 2. enum : memtype { ... } * 3. enum ident { ... } * 4. enum ident : memtype { ... } * 5. enum ident : memtype; * 6. enum ident; */ if (ed->memtype) { ed->memtype = typeSemantic(ed->memtype, ed->loc, sc); /* Check to see if memtype is forward referenced */ if (ed->memtype->ty == Tenum) { EnumDeclaration *sym = (EnumDeclaration *)ed->memtype->toDsymbol(sc); if (!sym->memtype || !sym->members || !sym->symtab || sym->_scope) { // memtype is forward referenced, so try again later ed->_scope = scx ? scx : sc->copy(); ed->_scope->setNoFree(); Module::addDeferredSemantic(ed); Module::dprogress = dprogress_save; //printf("\tdeferring %s\n", ed->toChars()); ed->semanticRun = PASSinit; return; } else // Ensure that semantic is run to detect. e.g. invalid forward references dsymbolSemantic(sym, sc); } if (ed->memtype->ty == Tvoid) { ed->error("base type must not be void"); ed->memtype = Type::terror; } if (ed->memtype->ty == Terror) { ed->errors = true; if (ed->members) { for (size_t i = 0; i < ed->members->length; i++) { Dsymbol *s = (*ed->members)[i]; s->errors = true; // poison all the members } } ed->semanticRun = PASSsemanticdone; return; } } ed->semanticRun = PASSsemanticdone; if (!ed->members) // enum ident : memtype; return; if (ed->members->length == 0) { ed->error("enum %s must have at least one member", ed->toChars()); ed->errors = true; return; } Module::dprogress++; Scope *sce; if (ed->isAnonymous()) sce = sc; else { sce = sc->push(ed); sce->parent = ed; } sce = sce->startCTFE(); sce->setNoFree(); // needed for getMaxMinValue() /* Each enum member gets the sce scope */ for (size_t i = 0; i < ed->members->length; i++) { EnumMember *em = (*ed->members)[i]->isEnumMember(); if (em) em->_scope = sce; } if (!ed->added) { /* addMember() is not called when the EnumDeclaration appears as a function statement, * so we have to do what addMember() does and install the enum members in the right symbol * table */ ScopeDsymbol *scopesym = NULL; if (ed->isAnonymous()) { /* Anonymous enum members get added to enclosing scope. */ for (Scope *sct = sce; 1; sct = sct->enclosing) { assert(sct); if (sct->scopesym) { scopesym = sct->scopesym; if (!sct->scopesym->symtab) sct->scopesym->symtab = new DsymbolTable(); break; } } } else { // Otherwise enum members are in the EnumDeclaration's symbol table scopesym = ed; } for (size_t i = 0; i < ed->members->length; i++) { EnumMember *em = (*ed->members)[i]->isEnumMember(); if (em) { em->ed = ed; em->addMember(sc, scopesym); } } } for (size_t i = 0; i < ed->members->length; i++) { EnumMember *em = (*ed->members)[i]->isEnumMember(); if (em) dsymbolSemantic(em, em->_scope); } //printf("defaultval = %lld\n", defaultval); //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); //printf("members = %s\n", ed->members->toChars()); } void visit(EnumMember *em) { //printf("EnumMember::semantic() %s\n", em->toChars()); if (em->errors || em->semanticRun >= PASSsemanticdone) return; if (em->semanticRun == PASSsemantic) { em->error("circular reference to enum member"); Lerrors: em->errors = true; em->semanticRun = PASSsemanticdone; return; } assert(em->ed); dsymbolSemantic(em->ed, sc); if (em->ed->errors) goto Lerrors; if (em->errors || em->semanticRun >= PASSsemanticdone) return; if (em->_scope) sc = em->_scope; if (!sc) return; em->semanticRun = PASSsemantic; em->protection = em->ed->isAnonymous() ? em->ed->protection : Prot(Prot::public_); em->linkage = LINKd; em->storage_class |= STCmanifest; // https://issues.dlang.org/show_bug.cgi?id=9701 if (em->ed->isAnonymous()) { if (em->userAttribDecl) em->userAttribDecl->userAttribDecl = em->ed->userAttribDecl; else em->userAttribDecl = em->ed->userAttribDecl; } // The first enum member is special bool first = (em == (*em->ed->members)[0]); if (em->origType) { em->origType = typeSemantic(em->origType, em->loc, sc); em->type = em->origType; assert(em->value()); // "type id;" is not a valid enum member declaration } if (em->value()) { Expression *e = em->value(); assert(e->dyncast() == DYNCAST_EXPRESSION); e = expressionSemantic(e, sc); e = resolveProperties(sc, e); e = e->ctfeInterpret(); if (e->op == TOKerror) goto Lerrors; if (first && !em->ed->memtype && !em->ed->isAnonymous()) { em->ed->memtype = e->type; if (em->ed->memtype->ty == Terror) { em->ed->errors = true; goto Lerrors; } if (em->ed->memtype->ty != Terror) { /* Bugzilla 11746: All of named enum members should have same type * with the first member. If the following members were referenced * during the first member semantic, their types should be unified. */ for (size_t i = 0; i < em->ed->members->length; i++) { EnumMember *enm = (*em->ed->members)[i]->isEnumMember(); if (!enm || enm == em || enm->semanticRun < PASSsemanticdone || enm->origType) continue; //printf("[%d] enm = %s, enm->semanticRun = %d\n", i, enm->toChars(), enm->semanticRun); Expression *ev = enm->value(); ev = ev->implicitCastTo(sc, em->ed->memtype); ev = ev->ctfeInterpret(); ev = ev->castTo(sc, em->ed->type); if (ev->op == TOKerror) em->ed->errors = true; enm->value() = ev; } if (em->ed->errors) { em->ed->memtype = Type::terror; goto Lerrors; } } } if (em->ed->memtype && !em->origType) { e = e->implicitCastTo(sc, em->ed->memtype); e = e->ctfeInterpret(); // save origValue for better json output em->origValue = e; if (!em->ed->isAnonymous()) { e = e->castTo(sc, em->ed->type); e = e->ctfeInterpret(); } } else if (em->origType) { e = e->implicitCastTo(sc, em->origType); e = e->ctfeInterpret(); assert(em->ed->isAnonymous()); // save origValue for better json output em->origValue = e; } em->value() = e; } else if (first) { Type *t; if (em->ed->memtype) t = em->ed->memtype; else { t = Type::tint32; if (!em->ed->isAnonymous()) em->ed->memtype = t; } Expression *e = new IntegerExp(em->loc, 0, Type::tint32); e = e->implicitCastTo(sc, t); e = e->ctfeInterpret(); // save origValue for better json output em->origValue = e; if (!em->ed->isAnonymous()) { e = e->castTo(sc, em->ed->type); e = e->ctfeInterpret(); } em->value() = e; } else { /* Find the previous enum member, * and set this to be the previous value + 1 */ EnumMember *emprev = NULL; for (size_t i = 0; i < em->ed->members->length; i++) { EnumMember *enm = (*em->ed->members)[i]->isEnumMember(); if (enm) { if (enm == em) break; emprev = enm; } } assert(emprev); if (emprev->semanticRun < PASSsemanticdone) // if forward reference dsymbolSemantic(emprev, emprev->_scope); // resolve it if (emprev->errors) goto Lerrors; Expression *eprev = emprev->value(); Type *tprev = eprev->type->equals(em->ed->type) ? em->ed->memtype : eprev->type; Expression *emax = tprev->getProperty(em->ed->loc, Id::max, 0); emax = expressionSemantic(emax, sc); emax = emax->ctfeInterpret(); // Set value to (eprev + 1). // But first check that (eprev != emax) assert(eprev); Expression *e = new EqualExp(TOKequal, em->loc, eprev, emax); e = expressionSemantic(e, sc); e = e->ctfeInterpret(); if (e->toInteger()) { em->error("initialization with (%s.%s + 1) causes overflow for type `%s`", emprev->ed->toChars(), emprev->toChars(), em->ed->type->toBasetype()->toChars()); goto Lerrors; } // Now set e to (eprev + 1) e = new AddExp(em->loc, eprev, new IntegerExp(em->loc, 1, Type::tint32)); e = expressionSemantic(e, sc); e = e->castTo(sc, eprev->type); e = e->ctfeInterpret(); // save origValue (without cast) for better json output if (e->op != TOKerror) // avoid duplicate diagnostics { assert(emprev->origValue); em->origValue = new AddExp(em->loc, emprev->origValue, new IntegerExp(em->loc, 1, Type::tint32)); em->origValue = expressionSemantic(em->origValue, sc); em->origValue = em->origValue->ctfeInterpret(); } if (e->op == TOKerror) goto Lerrors; if (e->type->isfloating()) { // Check that e != eprev (not always true for floats) Expression *etest = new EqualExp(TOKequal, em->loc, e, eprev); etest = expressionSemantic(etest, sc); etest = etest->ctfeInterpret(); if (etest->toInteger()) { em->error("has inexact value, due to loss of precision"); goto Lerrors; } } em->value() = e; } if (!em->origType) em->type = em->value()->type; assert(em->origValue); em->semanticRun = PASSsemanticdone; } void visit(TemplateDeclaration *tempdecl) { if (tempdecl->semanticRun != PASSinit) return; // semantic() already run // Remember templates defined in module object that we need to know about if (sc->_module && sc->_module->ident == Id::object) { if (tempdecl->ident == Id::RTInfo) Type::rtinfo = tempdecl; } /* Remember Scope for later instantiations, but make * a copy since attributes can change. */ if (!tempdecl->_scope) { tempdecl->_scope = sc->copy(); tempdecl->_scope->setNoFree(); } tempdecl->semanticRun = PASSsemantic; tempdecl->parent = sc->parent; tempdecl->protection = sc->protection; tempdecl->isstatic = tempdecl->toParent()->isModule() || (tempdecl->_scope->stc & STCstatic); if (!tempdecl->isstatic) { if (AggregateDeclaration *ad = tempdecl->parent->pastMixin()->isAggregateDeclaration()) ad->makeNested(); } // Set up scope for parameters ScopeDsymbol *paramsym = new ScopeDsymbol(); paramsym->parent = tempdecl->parent; Scope *paramscope = sc->push(paramsym); paramscope->stc = 0; if (global.params.doDocComments) { tempdecl->origParameters = new TemplateParameters(); tempdecl->origParameters->setDim(tempdecl->parameters->length); for (size_t i = 0; i < tempdecl->parameters->length; i++) { TemplateParameter *tp = (*tempdecl->parameters)[i]; (*tempdecl->origParameters)[i] = tp->syntaxCopy(); } } for (size_t i = 0; i < tempdecl->parameters->length; i++) { TemplateParameter *tp = (*tempdecl->parameters)[i]; if (!tp->declareParameter(paramscope)) { error(tp->loc, "parameter `%s` multiply defined", tp->ident->toChars()); tempdecl->errors = true; } if (!tpsemantic(tp, paramscope, tempdecl->parameters)) { tempdecl->errors = true; } if (i + 1 != tempdecl->parameters->length && tp->isTemplateTupleParameter()) { tempdecl->error("template tuple parameter must be last one"); tempdecl->errors = true; } } /* Calculate TemplateParameter::dependent */ TemplateParameters tparams; tparams.setDim(1); for (size_t i = 0; i < tempdecl->parameters->length; i++) { TemplateParameter *tp = (*tempdecl->parameters)[i]; tparams[0] = tp; for (size_t j = 0; j < tempdecl->parameters->length; j++) { // Skip cases like: X(T : T) if (i == j) continue; if (TemplateTypeParameter *ttp = (*tempdecl->parameters)[j]->isTemplateTypeParameter()) { if (reliesOnTident(ttp->specType, &tparams)) tp->dependent = true; } else if (TemplateAliasParameter *tap = (*tempdecl->parameters)[j]->isTemplateAliasParameter()) { if (reliesOnTident(tap->specType, &tparams) || reliesOnTident(isType(tap->specAlias), &tparams)) { tp->dependent = true; } } } } paramscope->pop(); // Compute again tempdecl->onemember = NULL; if (tempdecl->members) { Dsymbol *s; if (Dsymbol::oneMembers(tempdecl->members, &s, tempdecl->ident) && s) { tempdecl->onemember = s; s->parent = tempdecl; } } /* BUG: should check: * o no virtual functions or non-static data members of classes */ tempdecl->semanticRun = PASSsemanticdone; } void visit(TemplateInstance *ti) { templateInstanceSemantic(ti, sc, NULL); } void visit(TemplateMixin *tm) { if (tm->semanticRun != PASSinit) { // When a class/struct contains mixin members, and is done over // because of forward references, never reach here so semanticRun // has been reset to PASSinit. return; } tm->semanticRun = PASSsemantic; Scope *scx = NULL; if (tm->_scope) { sc = tm->_scope; scx = tm->_scope; // save so we don't make redundant copies tm->_scope = NULL; } /* Run semantic on each argument, place results in tiargs[], * then find best match template with tiargs */ if (!tm->findTempDecl(sc) || !tm->semanticTiargs(sc) || !tm->findBestMatch(sc, NULL)) { if (tm->semanticRun == PASSinit) // forward reference had occured { //printf("forward reference - deferring\n"); tm->_scope = scx ? scx : sc->copy(); tm->_scope->setNoFree(); Module::addDeferredSemantic(tm); return; } tm->inst = tm; tm->errors = true; return; // error recovery } TemplateDeclaration *tempdecl = tm->tempdecl->isTemplateDeclaration(); assert(tempdecl); if (!tm->ident) { /* Assign scope local unique identifier, as same as lambdas. */ const char *s = "__mixin"; if (FuncDeclaration *func = sc->parent->isFuncDeclaration()) { tm->symtab = func->localsymtab; if (tm->symtab) { // Inside template constraint, symtab is not set yet. goto L1; } } else { tm->symtab = sc->parent->isScopeDsymbol()->symtab; L1: assert(tm->symtab); int num = (int)dmd_aaLen(tm->symtab->tab) + 1; tm->ident = Identifier::generateId(s, num); tm->symtab->insert(tm); } } tm->inst = tm; tm->parent = sc->parent; /* Detect recursive mixin instantiations. */ for (Dsymbol *s = tm->parent; s; s = s->parent) { //printf("\ts = '%s'\n", s->toChars()); TemplateMixin *tmix = s->isTemplateMixin(); if (!tmix || tempdecl != tmix->tempdecl) continue; /* Different argument list lengths happen with variadic args */ if (tm->tiargs->length != tmix->tiargs->length) continue; for (size_t i = 0; i < tm->tiargs->length; i++) { RootObject *o = (*tm->tiargs)[i]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); RootObject *tmo = (*tmix->tiargs)[i]; if (ta) { Type *tmta = isType(tmo); if (!tmta) goto Lcontinue; if (!ta->equals(tmta)) goto Lcontinue; } else if (ea) { Expression *tme = isExpression(tmo); if (!tme || !ea->equals(tme)) goto Lcontinue; } else if (sa) { Dsymbol *tmsa = isDsymbol(tmo); if (sa != tmsa) goto Lcontinue; } else assert(0); } tm->error("recursive mixin instantiation"); return; Lcontinue: continue; } // Copy the syntax trees from the TemplateDeclaration tm->members = Dsymbol::arraySyntaxCopy(tempdecl->members); if (!tm->members) return; tm->symtab = new DsymbolTable(); for (Scope *sce = sc; 1; sce = sce->enclosing) { ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; if (sds) { sds->importScope(tm, Prot(Prot::public_)); break; } } Scope *scy = sc->push(tm); scy->parent = tm; tm->argsym = new ScopeDsymbol(); tm->argsym->parent = scy->parent; Scope *argscope = scy->push(tm->argsym); unsigned errorsave = global.errors; // Declare each template parameter as an alias for the argument type tm->declareParameters(argscope); // Add members to enclosing scope, as well as this scope for (size_t i = 0; i < tm->members->length; i++) { Dsymbol *s = (*tm->members)[i]; s->addMember(argscope, tm); //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); //printf("s->parent = %s\n", s->parent->toChars()); } // Do semantic() analysis on template instance members Scope *sc2 = argscope->push(tm); //size_t deferred_dim = Module::deferred.length; static int nest; //printf("%d\n", nest); if (++nest > global.recursionLimit) { global.gag = 0; // ensure error message gets printed tm->error("recursive expansion"); fatal(); } for (size_t i = 0; i < tm->members->length; i++) { Dsymbol *s = (*tm->members)[i]; s->setScope(sc2); } for (size_t i = 0; i < tm->members->length; i++) { Dsymbol *s = (*tm->members)[i]; s->importAll(sc2); } for (size_t i = 0; i < tm->members->length; i++) { Dsymbol *s = (*tm->members)[i]; dsymbolSemantic(s, sc2); } nest--; /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols. * Because the members would already call Module::addDeferredSemantic() for themselves. * See Struct, Class, Interface, and EnumDeclaration::semantic(). */ //if (!sc->func && Module::deferred.length > deferred_dim) {} AggregateDeclaration *ad = tm->toParent()->isAggregateDeclaration(); if (sc->func && !ad) { semantic2(tm, sc2); semantic3(tm, sc2); } // Give additional context info if error occurred during instantiation if (global.errors != errorsave) { tm->error("error instantiating"); tm->errors = true; } sc2->pop(); argscope->pop(); scy->pop(); } void visit(Nspace *ns) { if (ns->semanticRun != PASSinit) return; if (ns->_scope) { sc = ns->_scope; ns->_scope = NULL; } if (!sc) return; ns->semanticRun = PASSsemantic; ns->parent = sc->parent; if (ns->members) { assert(sc); sc = sc->push(ns); sc->linkage = LINKcpp; // note that namespaces imply C++ linkage sc->parent = ns; for (size_t i = 0; i < ns->members->length; i++) { Dsymbol *s = (*ns->members)[i]; s->importAll(sc); } for (size_t i = 0; i < ns->members->length; i++) { Dsymbol *s = (*ns->members)[i]; dsymbolSemantic(s, sc); } sc->pop(); } ns->semanticRun = PASSsemanticdone; } private: static bool isPointerToChar(Parameter *p) { if (TypePointer *tptr = p->type->isTypePointer()) { return tptr->next->ty == Tchar; } return false; } static bool isVa_list(Parameter *p, FuncDeclaration *funcdecl, Scope *sc) { return p->type->equals(target.va_listType(funcdecl->loc, sc)); } public: void funcDeclarationSemantic(FuncDeclaration *funcdecl) { TypeFunction *f; AggregateDeclaration *ad; InterfaceDeclaration *id; if (funcdecl->semanticRun != PASSinit && funcdecl->isFuncLiteralDeclaration()) { /* Member functions that have return types that are * forward references can have semantic() run more than * once on them. * See test\interface2.d, test20 */ return; } if (funcdecl->semanticRun >= PASSsemanticdone) return; assert(funcdecl->semanticRun <= PASSsemantic); funcdecl->semanticRun = PASSsemantic; if (funcdecl->_scope) { sc = funcdecl->_scope; funcdecl->_scope = NULL; } if (!sc || funcdecl->errors) return; funcdecl->parent = sc->parent; Dsymbol *parent = funcdecl->toParent(); funcdecl->foverrides.setDim(0); // reset in case semantic() is being retried for this function funcdecl->storage_class |= sc->stc & ~STCref; ad = funcdecl->isThis(); // Don't nest structs b/c of generated methods which should not access the outer scopes. // https://issues.dlang.org/show_bug.cgi?id=16627 if (ad && !funcdecl->generated) { funcdecl->storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized); ad->makeNested(); } if (sc->func) funcdecl->storage_class |= sc->func->storage_class & STCdisable; // Remove prefix storage classes silently. if ((funcdecl->storage_class & STC_TYPECTOR) && !(ad || funcdecl->isNested())) funcdecl->storage_class &= ~STC_TYPECTOR; //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", funcdecl->storage_class, sc->stc, Declaration::isFinal()); FuncLiteralDeclaration *fld = funcdecl->isFuncLiteralDeclaration(); if (fld && fld->treq) { Type *treq = fld->treq; assert(treq->nextOf()->ty == Tfunction); if (treq->ty == Tdelegate) fld->tok = TOKdelegate; else if (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction) fld->tok = TOKfunction; else assert(0); funcdecl->linkage = treq->nextOf()->toTypeFunction()->linkage; } else funcdecl->linkage = sc->linkage; funcdecl->inlining = sc->inlining; funcdecl->protection = sc->protection; funcdecl->userAttribDecl = sc->userAttribDecl; if (!funcdecl->originalType) funcdecl->originalType = funcdecl->type->syntaxCopy(); if (funcdecl->type->ty != Tfunction) { if (funcdecl->type->ty != Terror) { funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars()); funcdecl->type = Type::terror; } funcdecl->errors = true; return; } if (!funcdecl->type->deco) { sc = sc->push(); sc->stc |= funcdecl->storage_class & (STCdisable | STCdeprecated); // forward to function type TypeFunction *tf = funcdecl->type->toTypeFunction(); if (sc->func) { /* If the nesting parent is pure without inference, * then this function defaults to pure too. * * auto foo() pure { * auto bar() {} // become a weak purity funciton * class C { // nested class * auto baz() {} // become a weak purity funciton * } * * static auto boo() {} // typed as impure * // Even though, boo cannot call any impure functions. * // See also Expression::checkPurity(). * } */ if (tf->purity == PUREimpure && (funcdecl->isNested() || funcdecl->isThis())) { FuncDeclaration *fd = NULL; for (Dsymbol *p = funcdecl->toParent2(); p; p = p->toParent2()) { if (AggregateDeclaration *adx = p->isAggregateDeclaration()) { if (adx->isNested()) continue; break; } if ((fd = p->isFuncDeclaration()) != NULL) break; } /* If the parent's purity is inferred, then this function's purity needs * to be inferred first. */ if (fd && fd->isPureBypassingInference() >= PUREweak && !funcdecl->isInstantiated()) { tf->purity = PUREfwdref; // default to pure } } } if (tf->isref) sc->stc |= STCref; if (tf->isscope) sc->stc |= STCscope; if (tf->isnothrow) sc->stc |= STCnothrow; if (tf->isnogc) sc->stc |= STCnogc; if (tf->isproperty) sc->stc |= STCproperty; if (tf->purity == PUREfwdref) sc->stc |= STCpure; if (tf->trust != TRUSTdefault) sc->stc &= ~(STCsafe | STCsystem | STCtrusted); if (tf->trust == TRUSTsafe) sc->stc |= STCsafe; if (tf->trust == TRUSTsystem) sc->stc |= STCsystem; if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted; if (funcdecl->isCtorDeclaration()) { sc->flags |= SCOPEctor; Type *tret = ad->handleType(); assert(tret); tret = tret->addStorageClass(funcdecl->storage_class | sc->stc); tret = tret->addMod(funcdecl->type->mod); tf->next = tret; if (ad->isStructDeclaration()) sc->stc |= STCref; } // 'return' on a non-static class member function implies 'scope' as well if (ad && ad->isClassDeclaration() && (tf->isreturn || sc->stc & STCreturn) && !(sc->stc & STCstatic)) sc->stc |= STCscope; // If 'this' has no pointers, remove 'scope' as it has no meaning if (sc->stc & STCscope && ad && ad->isStructDeclaration() && !ad->type->hasPointers()) { sc->stc &= ~STCscope; tf->isscope = false; } sc->linkage = funcdecl->linkage; if (!tf->isNaked() && !(funcdecl->isThis() || funcdecl->isNested())) { OutBuffer buf; MODtoBuffer(&buf, tf->mod); funcdecl->error("without `this` cannot be %s", buf.peekChars()); tf->mod = 0; // remove qualifiers } /* Apply const, immutable, wild and shared storage class * to the function type. Do this before type semantic. */ StorageClass stc = funcdecl->storage_class; if (funcdecl->type->isImmutable()) stc |= STCimmutable; if (funcdecl->type->isConst()) stc |= STCconst; if (funcdecl->type->isShared() || funcdecl->storage_class & STCsynchronized) stc |= STCshared; if (funcdecl->type->isWild()) stc |= STCwild; switch (stc & STC_TYPECTOR) { case STCimmutable: case STCimmutable | STCconst: case STCimmutable | STCwild: case STCimmutable | STCwild | STCconst: case STCimmutable | STCshared: case STCimmutable | STCshared | STCconst: case STCimmutable | STCshared | STCwild: case STCimmutable | STCshared | STCwild | STCconst: // Don't use immutableOf(), as that will do a merge() funcdecl->type = funcdecl->type->makeImmutable(); break; case STCconst: funcdecl->type = funcdecl->type->makeConst(); break; case STCwild: funcdecl->type = funcdecl->type->makeWild(); break; case STCwild | STCconst: funcdecl->type = funcdecl->type->makeWildConst(); break; case STCshared: funcdecl->type = funcdecl->type->makeShared(); break; case STCshared | STCconst: funcdecl->type = funcdecl->type->makeSharedConst(); break; case STCshared | STCwild: funcdecl->type = funcdecl->type->makeSharedWild(); break; case STCshared | STCwild | STCconst: funcdecl->type = funcdecl->type->makeSharedWildConst(); break; case 0: break; default: assert(0); } funcdecl->type = typeSemantic(funcdecl->type, funcdecl->loc, sc); sc = sc->pop(); } if (funcdecl->type->ty != Tfunction) { if (funcdecl->type->ty != Terror) { funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars()); funcdecl->type = Type::terror; } funcdecl->errors = true; return; } else { // Merge back function attributes into 'originalType'. // It's used for mangling, ddoc, and json output. TypeFunction *tfo = funcdecl->originalType->toTypeFunction(); TypeFunction *tfx = funcdecl->type->toTypeFunction(); tfo->mod = tfx->mod; tfo->isscope = tfx->isscope; tfo->isscopeinferred = tfx->isscopeinferred; tfo->isref = tfx->isref; tfo->isnothrow = tfx->isnothrow; tfo->isnogc = tfx->isnogc; tfo->isproperty = tfx->isproperty; tfo->purity = tfx->purity; tfo->trust = tfx->trust; funcdecl->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR); } f = (TypeFunction *)funcdecl->type; if ((funcdecl->storage_class & STCauto) && !f->isref && !funcdecl->inferRetType) funcdecl->error("storage class `auto` has no effect if return type is not inferred"); /* Functions can only be 'scope' if they have a 'this' */ if (f->isscope && !funcdecl->isNested() && !ad) { funcdecl->error("functions cannot be scope"); } if (f->isreturn && !funcdecl->needThis() && !funcdecl->isNested()) { /* Non-static nested functions have a hidden 'this' pointer to which * the 'return' applies */ funcdecl->error("static member has no `this` to which `return` can apply"); } if (funcdecl->isAbstract() && !funcdecl->isVirtual()) { const char *sfunc; if (funcdecl->isStatic()) sfunc = "static"; else if (funcdecl->protection.kind == Prot::private_ || funcdecl->protection.kind == Prot::package_) sfunc = protectionToChars(funcdecl->protection.kind); else sfunc = "non-virtual"; funcdecl->error("%s functions cannot be abstract", sfunc); } if (funcdecl->isOverride() && !funcdecl->isVirtual()) { Prot::Kind kind = funcdecl->prot().kind; if ((kind == Prot::private_ || kind == Prot::package_) && funcdecl->isMember()) funcdecl->error("%s method is not virtual and cannot override", protectionToChars(kind)); else funcdecl->error("cannot override a non-virtual function"); } if (funcdecl->isAbstract() && funcdecl->isFinalFunc()) funcdecl->error("cannot be both final and abstract"); if (const unsigned pors = sc->flags & (SCOPEprintf | SCOPEscanf)) { /* printf/scanf-like functions must be of the form: * extern (C/C++) T printf([parameters...], const(char)* format, ...); * or: * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); */ const size_t nparams = f->parameterList.length(); if ((f->linkage == LINKc || f->linkage == LINKcpp) && ((f->parameterList.varargs == VARARGvariadic && nparams >= 1 && isPointerToChar(f->parameterList[nparams - 1])) || (f->parameterList.varargs == VARARGnone && nparams >= 2 && isPointerToChar(f->parameterList[nparams - 2]) && isVa_list(f->parameterList[nparams - 1], funcdecl, sc)) ) ) { funcdecl->flags |= (pors == SCOPEprintf) ? FUNCFLAGprintf : FUNCFLAGscanf; } else { const char *p = (pors == SCOPEprintf ? Id::printf : Id::scanf)->toChars(); if (f->parameterList.varargs == VARARGvariadic) { funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`" " not `%s`", p, f->next->toChars(), funcdecl->toChars(), funcdecl->type->toChars()); } else { funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`", p, f->next->toChars(), funcdecl->toChars()); } } } id = parent->isInterfaceDeclaration(); if (id) { funcdecl->storage_class |= STCabstract; if (funcdecl->isCtorDeclaration() || funcdecl->isPostBlitDeclaration() || funcdecl->isDtorDeclaration() || funcdecl->isInvariantDeclaration() || funcdecl->isNewDeclaration() || funcdecl->isDelete()) funcdecl->error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id->toChars()); if (funcdecl->fbody && funcdecl->isVirtual()) funcdecl->error("function body only allowed in final functions in interface %s", id->toChars()); } if (UnionDeclaration *ud = parent->isUnionDeclaration()) { if (funcdecl->isPostBlitDeclaration() || funcdecl->isDtorDeclaration() || funcdecl->isInvariantDeclaration()) funcdecl->error("destructors, postblits and invariants are not allowed in union %s", ud->toChars()); } if (parent->isStructDeclaration()) { if (funcdecl->isCtorDeclaration()) { goto Ldone; } } if (ClassDeclaration *cd = parent->isClassDeclaration()) { if (funcdecl->isCtorDeclaration()) { goto Ldone; } if (funcdecl->storage_class & STCabstract) cd->isabstract = ABSyes; // if static function, do not put in vtbl[] if (!funcdecl->isVirtual()) { //printf("\tnot virtual\n"); goto Ldone; } // Suppress further errors if the return type is an error if (funcdecl->type->nextOf() == Type::terror) goto Ldone; bool may_override = false; for (size_t i = 0; i < cd->baseclasses->length; i++) { BaseClass *b = (*cd->baseclasses)[i]; ClassDeclaration *cbd = b->type->toBasetype()->isClassHandle(); if (!cbd) continue; for (size_t j = 0; j < cbd->vtbl.length; j++) { FuncDeclaration *f2 = cbd->vtbl[j]->isFuncDeclaration(); if (!f2 || f2->ident != funcdecl->ident) continue; if (cbd->parent && cbd->parent->isTemplateInstance()) { if (!f2->functionSemantic()) goto Ldone; } may_override = true; } } if (may_override && funcdecl->type->nextOf() == NULL) { /* If same name function exists in base class but 'this' is auto return, * cannot find index of base class's vtbl[] to override. */ funcdecl->error("return type inference is not supported if may override base class function"); } /* Find index of existing function in base class's vtbl[] to override * (the index will be the same as in cd's current vtbl[]) */ int vi = cd->baseClass ? funcdecl->findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length) : -1; bool doesoverride = false; switch (vi) { case -1: Lintro: /* Didn't find one, so * This is an 'introducing' function which gets a new * slot in the vtbl[]. */ // Verify this doesn't override previous final function if (cd->baseClass) { Dsymbol *s = cd->baseClass->search(funcdecl->loc, funcdecl->ident); if (s) { FuncDeclaration *f2 = s->isFuncDeclaration(); if (f2) { f2 = f2->overloadExactMatch(funcdecl->type); if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_) funcdecl->error("cannot override final function %s", f2->toPrettyChars()); } } } /* These quirky conditions mimic what VC++ appears to do */ if (global.params.mscoff && cd->isCPPclass() && cd->baseClass && cd->baseClass->vtbl.length) { /* if overriding an interface function, then this is not * introducing and don't put it in the class vtbl[] */ funcdecl->interfaceVirtual = funcdecl->overrideInterface(); if (funcdecl->interfaceVirtual) { //printf("\tinterface function %s\n", funcdecl->toChars()); cd->vtblFinal.push(funcdecl); goto Linterfaces; } } if (funcdecl->isFinalFunc()) { // Don't check here, as it may override an interface function //if (funcdecl->isOverride()) //funcdecl->error("is marked as override, but does not override any function"); cd->vtblFinal.push(funcdecl); } else { //printf("\tintroducing function %s\n", funcdecl->toChars()); funcdecl->introducing = 1; if (cd->isCPPclass() && target.cpp.reverseOverloads) { // with dmc, overloaded functions are grouped and in reverse order funcdecl->vtblIndex = (int)cd->vtbl.length; for (int i = 0; i < (int)cd->vtbl.length; i++) { if (cd->vtbl[i]->ident == funcdecl->ident && cd->vtbl[i]->parent == parent) { funcdecl->vtblIndex = (int)i; break; } } // shift all existing functions back for (int i = (int)cd->vtbl.length; i > funcdecl->vtblIndex; i--) { FuncDeclaration *fd = cd->vtbl[i-1]->isFuncDeclaration(); assert(fd); fd->vtblIndex++; } cd->vtbl.insert(funcdecl->vtblIndex, funcdecl); } else { // Append to end of vtbl[] vi = (int)cd->vtbl.length; cd->vtbl.push(funcdecl); funcdecl->vtblIndex = vi; } } break; case -2: // can't determine because of forward references funcdecl->errors = true; return; default: { FuncDeclaration *fdv = cd->baseClass->vtbl[vi]->isFuncDeclaration(); FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration(); // This function is covariant with fdv if (fdc == funcdecl) { doesoverride = true; break; } if (fdc->toParent() == parent) { //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", // vi, funcdecl, funcdecl->toChars(), funcdecl->type->toChars(), funcdecl->loc.toChars(), // fdc, fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(), // fdv, fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars()); // fdc overrides fdv exactly, then this introduces new function. if (fdc->type->mod == fdv->type->mod && funcdecl->type->mod != fdv->type->mod) goto Lintro; } // This function overrides fdv if (fdv->isFinalFunc()) funcdecl->error("cannot override final function %s", fdv->toPrettyChars()); if (!funcdecl->isOverride()) { if (fdv->isFuture()) { ::deprecation(funcdecl->loc, "@__future base class method %s is being overridden by %s; rename the latter", fdv->toPrettyChars(), funcdecl->toPrettyChars()); // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] goto Lintro; } else { int vi2 = funcdecl->findVtblIndex(&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length, false); if (vi2 < 0) // https://issues.dlang.org/show_bug.cgi?id=17349 ::deprecation(funcdecl->loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", fdv->toPrettyChars(), funcdecl->toPrettyChars()); else error(funcdecl->loc, "implicitly overriding base class method %s with %s deprecated; add `override` attribute", fdv->toPrettyChars(), funcdecl->toPrettyChars()); } } doesoverride = true; if (fdc->toParent() == parent) { // If both are mixins, or both are not, then error. // If either is not, the one that is not overrides the other. bool thismixin = funcdecl->parent->isClassDeclaration() != NULL; bool fdcmixin = fdc->parent->isClassDeclaration() != NULL; if (thismixin == fdcmixin) { funcdecl->error("multiple overrides of same function"); } else if (!thismixin) // fdc overrides fdv { // this doesn't override any function break; } } cd->vtbl[vi] = funcdecl; funcdecl->vtblIndex = vi; /* Remember which functions this overrides */ funcdecl->foverrides.push(fdv); /* This works by whenever this function is called, * it actually returns tintro, which gets dynamically * cast to type. But we know that tintro is a base * of type, so we could optimize it by not doing a * dynamic cast, but just subtracting the isBaseOf() * offset if the value is != null. */ if (fdv->tintro) funcdecl->tintro = fdv->tintro; else if (!funcdecl->type->equals(fdv->type)) { /* Only need to have a tintro if the vptr * offsets differ */ int offset; if (fdv->type->nextOf()->isBaseOf(funcdecl->type->nextOf(), &offset)) { funcdecl->tintro = fdv->type; } } break; } } /* Go through all the interface bases. * If this function is covariant with any members of those interface * functions, set the tintro. */ Linterfaces: for (size_t i = 0; i < cd->interfaces.length; i++) { BaseClass *b = cd->interfaces.ptr[i]; vi = funcdecl->findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.length); switch (vi) { case -1: break; case -2: // can't determine because of forward references funcdecl->errors = true; return; default: { FuncDeclaration *fdv = (FuncDeclaration *)b->sym->vtbl[vi]; Type *ti = NULL; /* Remember which functions this overrides */ funcdecl->foverrides.push(fdv); /* Should we really require 'override' when implementing * an interface function? */ //if (!funcdecl->isOverride()) //warning(funcdecl->loc, "overrides base class function %s, but is not marked with `override`", fdv->toPrettyChars()); if (fdv->tintro) ti = fdv->tintro; else if (!funcdecl->type->equals(fdv->type)) { /* Only need to have a tintro if the vptr * offsets differ */ int offset; if (fdv->type->nextOf()->isBaseOf(funcdecl->type->nextOf(), &offset)) { ti = fdv->type; } } if (ti) { if (funcdecl->tintro) { if (!funcdecl->tintro->nextOf()->equals(ti->nextOf()) && !funcdecl->tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) && !ti->nextOf()->isBaseOf(funcdecl->tintro->nextOf(), NULL)) { funcdecl->error("incompatible covariant types %s and %s", funcdecl->tintro->toChars(), ti->toChars()); } } funcdecl->tintro = ti; } goto L2; } } } if (!doesoverride && funcdecl->isOverride() && (funcdecl->type->nextOf() || !may_override)) { BaseClass *bc = NULL; Dsymbol *s = NULL; for (size_t i = 0; i < cd->baseclasses->length; i++) { bc = (*cd->baseclasses)[i]; s = bc->sym->search_correct(funcdecl->ident); if (s) break; } if (s) funcdecl->error("does not override any function, did you mean to override `%s%s`?", bc->sym->isCPPclass() ? "extern (C++) " : "", s->toPrettyChars()); else funcdecl->error("does not override any function"); } L2: ; /* Go through all the interface bases. * Disallow overriding any final functions in the interface(s). */ for (size_t i = 0; i < cd->interfaces.length; i++) { BaseClass *b = cd->interfaces.ptr[i]; if (b->sym) { Dsymbol *s = search_function(b->sym, funcdecl->ident); if (s) { FuncDeclaration *f2 = s->isFuncDeclaration(); if (f2) { f2 = f2->overloadExactMatch(funcdecl->type); if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_) funcdecl->error("cannot override final function %s.%s", b->sym->toChars(), f2->toPrettyChars()); } } } } if (funcdecl->isOverride()) { if (funcdecl->storage_class & STCdisable) funcdecl->deprecation("overridden functions cannot be annotated @disable"); if (funcdecl->isDeprecated()) funcdecl->deprecation("deprecated functions cannot be annotated @disable"); } } else if (funcdecl->isOverride() && !parent->isTemplateInstance()) funcdecl->error("override only applies to class member functions"); // Reflect this->type to f because it could be changed by findVtblIndex f = funcdecl->type->toTypeFunction(); Ldone: /* Contracts can only appear without a body when they are virtual interface functions */ if (!funcdecl->fbody && !allowsContractWithoutBody(funcdecl)) funcdecl->error("in and out contracts can only appear without a body when they are virtual interface functions or abstract"); /* Do not allow template instances to add virtual functions * to a class. */ if (funcdecl->isVirtual()) { TemplateInstance *ti = parent->isTemplateInstance(); if (ti) { // Take care of nested templates while (1) { TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); if (!ti2) break; ti = ti2; } // If it's a member template ClassDeclaration *cd = ti->tempdecl->isClassMember(); if (cd) { funcdecl->error("cannot use template to add virtual function to class `%s`", cd->toChars()); } } } if (funcdecl->isMain()) funcdecl->checkDmain(); // Check main() parameters and return type /* Purity and safety can be inferred for some functions by examining * the function body. */ if (canInferAttributes(funcdecl, sc)) initInferAttributes(funcdecl); Module::dprogress++; funcdecl->semanticRun = PASSsemanticdone; /* Save scope for possible later use (if we need the * function internals) */ funcdecl->_scope = sc->copy(); funcdecl->_scope->setNoFree(); static bool printedMain = false; // semantic might run more than once if (global.params.verbose && !printedMain) { const char *type = funcdecl->isMain() ? "main" : funcdecl->isWinMain() ? "winmain" : funcdecl->isDllMain() ? "dllmain" : (const char *)NULL; Module *mod = sc->_module; if (type && mod) { printedMain = true; const char *name = mod->srcfile->toChars(); const char *path = FileName::searchPath(global.path, name, true); message("entry %-10s\t%s", type, path ? path : name); } } if (funcdecl->fbody && funcdecl->isMain() && sc->_module->isRoot()) Compiler::genCmain(sc); assert(funcdecl->type->ty != Terror || funcdecl->errors); // semantic for parameters' UDAs const size_t nparams = f->parameterList.length(); for (size_t i = 0; i < nparams; i++) { Parameter *param = f->parameterList[i]; if (param && param->userAttribDecl) dsymbolSemantic(param->userAttribDecl, sc); } } // Do the semantic analysis on the external interface to the function. void visit(FuncDeclaration *funcdecl) { funcDeclarationSemantic(funcdecl); } void visit(CtorDeclaration *ctd) { //printf("CtorDeclaration::semantic() %s\n", ctd->toChars()); if (ctd->semanticRun >= PASSsemanticdone) return; if (ctd->_scope) { sc = ctd->_scope; ctd->_scope = NULL; } ctd->parent = sc->parent; Dsymbol *p = ctd->toParent2(); AggregateDeclaration *ad = p->isAggregateDeclaration(); if (!ad) { error(ctd->loc, "constructor can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); ctd->type = Type::terror; ctd->errors = true; return; } sc = sc->push(); sc->stc &= ~STCstatic; // not a static constructor sc->flags |= SCOPEctor; funcDeclarationSemantic(ctd); sc->pop(); if (ctd->errors) return; TypeFunction *tf = ctd->type->toTypeFunction(); /* See if it's the default constructor * But, template constructor should not become a default constructor. */ if (ad && (!ctd->parent->isTemplateInstance() || ctd->parent->isTemplateMixin())) { const size_t dim = tf->parameterList.length(); if (StructDeclaration *sd = ad->isStructDeclaration()) { if (dim == 0 && tf->parameterList.varargs == VARARGnone) // empty default ctor w/o any varargs { if (ctd->fbody || !(ctd->storage_class & STCdisable) || dim) { ctd->error("default constructor for structs only allowed " "with @disable, no body, and no parameters"); ctd->storage_class |= STCdisable; ctd->fbody = NULL; } sd->noDefaultCtor = true; } else if (dim == 0 && tf->parameterList.varargs) // allow varargs only ctor { } else if (dim && tf->parameterList[0]->defaultArg) { // if the first parameter has a default argument, then the rest does as well if (ctd->storage_class & STCdisable) { ctd->deprecation("@disable'd constructor cannot have default " "arguments for all parameters."); deprecationSupplemental(ctd->loc, "Use @disable this(); if you want to disable default initialization."); } else ctd->deprecation("all parameters have default arguments, " "but structs cannot have default constructors."); } } else if (dim == 0 && tf->parameterList.varargs == VARARGnone) { ad->defaultCtor = ctd; } } } void visit(PostBlitDeclaration *pbd) { //printf("PostBlitDeclaration::semantic() %s\n", pbd->toChars()); //printf("ident: %s, %s, %p, %p\n", pbd->ident->toChars(), Id::dtor->toChars(), pbd->ident, Id::dtor); //printf("stc = x%llx\n", sc->stc); if (pbd->semanticRun >= PASSsemanticdone) return; if (pbd->_scope) { sc = pbd->_scope; pbd->_scope = NULL; } pbd->parent = sc->parent; Dsymbol *p = pbd->toParent2(); StructDeclaration *ad = p->isStructDeclaration(); if (!ad) { error(pbd->loc, "postblit can only be a member of struct/union, not %s %s", p->kind(), p->toChars()); pbd->type = Type::terror; pbd->errors = true; return; } if (pbd->ident == Id::postblit && pbd->semanticRun < PASSsemantic) ad->postblits.push(pbd); if (!pbd->type) pbd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, pbd->storage_class); sc = sc->push(); sc->stc &= ~STCstatic; // not static sc->linkage = LINKd; funcDeclarationSemantic(pbd); sc->pop(); } void visit(DtorDeclaration *dd) { //printf("DtorDeclaration::semantic() %s\n", dd->toChars()); //printf("ident: %s, %s, %p, %p\n", dd->ident->toChars(), Id::dtor->toChars(), dd->ident, Id::dtor); if (dd->semanticRun >= PASSsemanticdone) return; if (dd->_scope) { sc = dd->_scope; dd->_scope = NULL; } dd->parent = sc->parent; Dsymbol *p = dd->toParent2(); AggregateDeclaration *ad = p->isAggregateDeclaration(); if (!ad) { error(dd->loc, "destructor can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); dd->type = Type::terror; dd->errors = true; return; } if (dd->ident == Id::dtor && dd->semanticRun < PASSsemantic) ad->dtors.push(dd); if (!dd->type) dd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, dd->storage_class); sc = sc->push(); sc->stc &= ~STCstatic; // not a static destructor if (sc->linkage != LINKcpp) sc->linkage = LINKd; funcDeclarationSemantic(dd); sc->pop(); } void visit(StaticCtorDeclaration *scd) { //printf("StaticCtorDeclaration::semantic()\n"); if (scd->semanticRun >= PASSsemanticdone) return; if (scd->_scope) { sc = scd->_scope; scd->_scope = NULL; } scd->parent = sc->parent; Dsymbol *p = scd->parent->pastMixin(); if (!p->isScopeDsymbol()) { const char *s = (scd->isSharedStaticCtorDeclaration() ? "shared " : ""); error(scd->loc, "%sstatic constructor can only be member of module/aggregate/template, not %s %s", s, p->kind(), p->toChars()); scd->type = Type::terror; scd->errors = true; return; } if (!scd->type) scd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, scd->storage_class); /* If the static ctor appears within a template instantiation, * it could get called multiple times by the module constructors * for different modules. Thus, protect it with a gate. */ if (scd->isInstantiated() && scd->semanticRun < PASSsemantic) { /* Add this prefix to the function: * static int gate; * if (++gate != 1) return; * Note that this is not thread safe; should not have threads * during static construction. */ VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL); v->storage_class = STCtemp | (scd->isSharedStaticCtorDeclaration() ? STCstatic : STCtls); Statements *sa = new Statements(); Statement *s = new ExpStatement(Loc(), v); sa->push(s); Expression *e = new IdentifierExp(Loc(), v->ident); e = new AddAssignExp(Loc(), e, new IntegerExp(1)); e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(1)); s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc()); sa->push(s); if (scd->fbody) sa->push(scd->fbody); scd->fbody = new CompoundStatement(Loc(), sa); } funcDeclarationSemantic(scd); // We're going to need ModuleInfo Module *m = scd->getModule(); if (!m) m = sc->_module; if (m) { m->needmoduleinfo = 1; //printf("module1 %s needs moduleinfo\n", m->toChars()); } } void visit(StaticDtorDeclaration *sdd) { if (sdd->semanticRun >= PASSsemanticdone) return; if (sdd->_scope) { sc = sdd->_scope; sdd->_scope = NULL; } sdd->parent = sc->parent; Dsymbol *p = sdd->parent->pastMixin(); if (!p->isScopeDsymbol()) { const char *s = (sdd->isSharedStaticDtorDeclaration() ? "shared " : ""); error(sdd->loc, "%sstatic destructor can only be member of module/aggregate/template, not %s %s", s, p->kind(), p->toChars()); sdd->type = Type::terror; sdd->errors = true; return; } if (!sdd->type) sdd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, sdd->storage_class); /* If the static ctor appears within a template instantiation, * it could get called multiple times by the module constructors * for different modules. Thus, protect it with a gate. */ if (sdd->isInstantiated() && sdd->semanticRun < PASSsemantic) { /* Add this prefix to the function: * static int gate; * if (--gate != 0) return; * Increment gate during constructor execution. * Note that this is not thread safe; should not have threads * during static destruction. */ VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL); v->storage_class = STCtemp | (sdd->isSharedStaticDtorDeclaration() ? STCstatic : STCtls); Statements *sa = new Statements(); Statement *s = new ExpStatement(Loc(), v); sa->push(s); Expression *e = new IdentifierExp(Loc(), v->ident); e = new AddAssignExp(Loc(), e, new IntegerExp(-1)); e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(0)); s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc()); sa->push(s); if (sdd->fbody) sa->push(sdd->fbody); sdd->fbody = new CompoundStatement(Loc(), sa); sdd->vgate = v; } funcDeclarationSemantic(sdd); // We're going to need ModuleInfo Module *m = sdd->getModule(); if (!m) m = sc->_module; if (m) { m->needmoduleinfo = 1; //printf("module2 %s needs moduleinfo\n", m->toChars()); } } void visit(InvariantDeclaration *invd) { if (invd->semanticRun >= PASSsemanticdone) return; if (invd->_scope) { sc = invd->_scope; invd->_scope = NULL; } invd->parent = sc->parent; Dsymbol *p = invd->parent->pastMixin(); AggregateDeclaration *ad = p->isAggregateDeclaration(); if (!ad) { error(invd->loc, "invariant can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); invd->type = Type::terror; invd->errors = true; return; } if (invd->ident != Id::classInvariant && invd->semanticRun < PASSsemantic && !ad->isUnionDeclaration() // users are on their own with union fields ) ad->invs.push(invd); if (!invd->type) invd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, invd->storage_class); sc = sc->push(); sc->stc &= ~STCstatic; // not a static invariant sc->stc |= STCconst; // invariant() is always const sc->flags = (sc->flags & ~SCOPEcontract) | SCOPEinvariant; sc->linkage = LINKd; funcDeclarationSemantic(invd); sc->pop(); } void visit(UnitTestDeclaration *utd) { if (utd->semanticRun >= PASSsemanticdone) return; if (utd->_scope) { sc = utd->_scope; utd->_scope = NULL; } utd->protection = sc->protection; utd->parent = sc->parent; Dsymbol *p = utd->parent->pastMixin(); if (!p->isScopeDsymbol()) { error(utd->loc, "unittest can only be a member of module/aggregate/template, not %s %s", p->kind(), p->toChars()); utd->type = Type::terror; utd->errors = true; return; } if (global.params.useUnitTests) { if (!utd->type) utd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, utd->storage_class); Scope *sc2 = sc->push(); sc2->linkage = LINKd; funcDeclarationSemantic(utd); sc2->pop(); } } void visit(NewDeclaration *nd) { //printf("NewDeclaration::semantic()\n"); if (nd->semanticRun >= PASSsemanticdone) return; if (nd->_scope) { sc = nd->_scope; nd->_scope = NULL; } nd->parent = sc->parent; Dsymbol *p = nd->parent->pastMixin(); if (!p->isAggregateDeclaration()) { error(nd->loc, "allocator can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); nd->type = Type::terror; nd->errors = true; return; } Type *tret = Type::tvoid->pointerTo(); if (!nd->type) nd->type = new TypeFunction(ParameterList(nd->parameters, nd->varargs), tret, LINKd, nd->storage_class); nd->type = typeSemantic(nd->type, nd->loc, sc); // Check that there is at least one argument of type size_t TypeFunction *tf = nd->type->toTypeFunction(); if (tf->parameterList.length() < 1) { nd->error("at least one argument of type size_t expected"); } else { Parameter *fparam = tf->parameterList[0]; if (!fparam->type->equals(Type::tsize_t)) nd->error("first argument must be type size_t, not %s", fparam->type->toChars()); } funcDeclarationSemantic(nd); } void visit(DeleteDeclaration *deld) { //printf("DeleteDeclaration::semantic()\n"); if (deld->semanticRun >= PASSsemanticdone) return; if (deld->_scope) { sc = deld->_scope; deld->_scope = NULL; } deld->parent = sc->parent; Dsymbol *p = deld->parent->pastMixin(); if (!p->isAggregateDeclaration()) { error(deld->loc, "deallocator can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); deld->type = Type::terror; deld->errors = true; return; } if (!deld->type) deld->type = new TypeFunction(ParameterList(deld->parameters), Type::tvoid, LINKd, deld->storage_class); deld->type = typeSemantic(deld->type, deld->loc, sc); // Check that there is only one argument of type void* TypeFunction *tf = deld->type->toTypeFunction(); if (tf->parameterList.length() != 1) { deld->error("one argument of type void* expected"); } else { Parameter *fparam = tf->parameterList[0]; if (!fparam->type->equals(Type::tvoid->pointerTo())) deld->error("one argument of type void* expected, not %s", fparam->type->toChars()); } funcDeclarationSemantic(deld); } void visit(StructDeclaration *sd) { //printf("StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", sd, sd->parent->toChars(), sd->toChars(), sizeok); //static int count; if (++count == 20) halt(); if (sd->semanticRun >= PASSsemanticdone) return; unsigned errors = global.errors; //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", sd, sd->parent->toChars(), sd->toChars(), sizeok); Scope *scx = NULL; if (sd->_scope) { sc = sd->_scope; scx = sd->_scope; // save so we don't make redundant copies sd->_scope = NULL; } if (!sd->parent) { assert(sc->parent && sc->func); sd->parent = sc->parent; } assert(sd->parent && !sd->isAnonymous()); if (sd->errors) sd->type = Type::terror; if (sd->semanticRun == PASSinit) sd->type = sd->type->addSTC(sc->stc | sd->storage_class); sd->type = typeSemantic(sd->type, sd->loc, sc); if (sd->type->ty == Tstruct && ((TypeStruct *)sd->type)->sym != sd) { TemplateInstance *ti = ((TypeStruct *)sd->type)->sym->isInstantiated(); if (ti && isError(ti)) ((TypeStruct *)sd->type)->sym = sd; } // Ungag errors when not speculative Ungag ungag = sd->ungagSpeculative(); if (sd->semanticRun == PASSinit) { sd->protection = sc->protection; sd->alignment = sc->alignment(); sd->storage_class |= sc->stc; if (sd->storage_class & STCdeprecated) sd->isdeprecated = true; if (sd->storage_class & STCabstract) sd->error("structs, unions cannot be abstract"); sd->userAttribDecl = sc->userAttribDecl; if (sc->linkage == LINKcpp) sd->classKind = ClassKind::cpp; } else if (sd->symtab && !scx) { return; } sd->semanticRun = PASSsemantic; if (!sd->members) // if opaque declaration { sd->semanticRun = PASSsemanticdone; return; } if (!sd->symtab) { sd->symtab = new DsymbolTable(); for (size_t i = 0; i < sd->members->length; i++) { Dsymbol *s = (*sd->members)[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), sd->toChars()); s->addMember(sc, sd); } } Scope *sc2 = sd->newScope(sc); /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ for (size_t i = 0; i < sd->members->length; i++) { Dsymbol *s = (*sd->members)[i]; //printf("struct: setScope %s %s\n", s->kind(), s->toChars()); s->setScope(sc2); } for (size_t i = 0; i < sd->members->length; i++) { Dsymbol *s = (*sd->members)[i]; s->importAll(sc2); } for (size_t i = 0; i < sd->members->length; i++) { Dsymbol *s = (*sd->members)[i]; dsymbolSemantic(s, sc2); } if (!sd->determineFields()) { assert(sd->type->ty == Terror); sc2->pop(); sd->semanticRun = PASSsemanticdone; return; } /* Following special member functions creation needs semantic analysis * completion of sub-structs in each field types. For example, buildDtor * needs to check existence of elaborate dtor in type of each fields. * See the case in compilable/test14838.d */ for (size_t i = 0; i < sd->fields.length; i++) { VarDeclaration *v = sd->fields[i]; Type *tb = v->type->baseElemOf(); if (tb->ty != Tstruct) continue; StructDeclaration *sdec = ((TypeStruct *)tb)->sym; if (sdec->semanticRun >= PASSsemanticdone) continue; sc2->pop(); sd->_scope = scx ? scx : sc->copy(); sd->_scope->setNoFree(); Module::addDeferredSemantic(sd); //printf("\tdeferring %s\n", sd->toChars()); return; } /* Look for special member functions. */ sd->aggNew = (NewDeclaration *)sd->search(Loc(), Id::classNew); sd->aggDelete = (DeleteDeclaration *)sd->search(Loc(), Id::classDelete); // Look for the constructor sd->ctor = sd->searchCtor(); sd->dtor = buildDtor(sd, sc2); sd->postblit = buildPostBlit(sd, sc2); buildOpAssign(sd, sc2); buildOpEquals(sd, sc2); if (global.params.useTypeInfo && Type::dtypeinfo) // these functions are used for TypeInfo { sd->xeq = buildXopEquals(sd, sc2); sd->xcmp = buildXopCmp(sd, sc2); sd->xhash = buildXtoHash(sd, sc2); } sd->inv = buildInv(sd, sc2); Module::dprogress++; sd->semanticRun = PASSsemanticdone; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd->toChars()); sc2->pop(); if (sd->ctor) { Dsymbol *scall = sd->search(Loc(), Id::call); if (scall) { unsigned xerrors = global.startGagging(); sc = sc->push(); sc->tinst = NULL; sc->minst = NULL; FuncDeclaration *fcall = resolveFuncCall(sd->loc, sc, scall, NULL, NULL, NULL, 1); sc = sc->pop(); global.endGagging(xerrors); if (fcall && fcall->isStatic()) { sd->error(fcall->loc, "`static opCall` is hidden by constructors and can never be called"); errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with `static opCall`."); } } } if (sd->type->ty == Tstruct && ((TypeStruct *)sd->type)->sym != sd) { // https://issues.dlang.org/show_bug.cgi?id=19024 StructDeclaration *sym = ((TypeStruct *)sd->type)->sym; sd->error("already exists at %s. Perhaps in another function with the same name?", sym->loc.toChars()); } if (global.errors != errors) { // The type is no good. sd->type = Type::terror; sd->errors = true; if (sd->deferred) sd->deferred->errors = true; } if (sd->deferred && !global.gag) { semantic2(sd->deferred, sc); semantic3(sd->deferred, sc); } } void interfaceSemantic(ClassDeclaration *cd) { cd->vtblInterfaces = new BaseClasses(); cd->vtblInterfaces->reserve(cd->interfaces.length); for (size_t i = 0; i < cd->interfaces.length; i++) { BaseClass *b = cd->interfaces.ptr[i]; cd->vtblInterfaces->push(b); b->copyBaseInterfaces(cd->vtblInterfaces); } } void visit(ClassDeclaration *cldec) { //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec); //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); //printf("sc->stc = %x\n", sc->stc); //{ static int n; if (++n == 20) *(char*)0=0; } if (cldec->semanticRun >= PASSsemanticdone) return; unsigned errors = global.errors; //printf("+ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec); Scope *scx = NULL; if (cldec->_scope) { sc = cldec->_scope; scx = cldec->_scope; // save so we don't make redundant copies cldec->_scope = NULL; } if (!cldec->parent) { assert(sc->parent); cldec->parent = sc->parent; } if (cldec->errors) cldec->type = Type::terror; cldec->type = typeSemantic(cldec->type, cldec->loc, sc); if (cldec->type->ty == Tclass && ((TypeClass *)cldec->type)->sym != cldec) { TemplateInstance *ti = ((TypeClass *)cldec->type)->sym->isInstantiated(); if (ti && isError(ti)) ((TypeClass *)cldec->type)->sym = cldec; } // Ungag errors when not speculative Ungag ungag = cldec->ungagSpeculative(); if (cldec->semanticRun == PASSinit) { cldec->protection = sc->protection; cldec->storage_class |= sc->stc; if (cldec->storage_class & STCdeprecated) cldec->isdeprecated = true; if (cldec->storage_class & STCauto) cldec->error("storage class `auto` is invalid when declaring a class, did you mean to use `scope`?"); if (cldec->storage_class & STCscope) cldec->isscope = true; if (cldec->storage_class & STCabstract) cldec->isabstract = ABSyes; cldec->userAttribDecl = sc->userAttribDecl; if (sc->linkage == LINKcpp) cldec->classKind = ClassKind::cpp; if (sc->linkage == LINKobjc) objc()->setObjc(cldec); } else if (cldec->symtab && !scx) { return; } cldec->semanticRun = PASSsemantic; if (cldec->baseok < BASEOKdone) { cldec->baseok = BASEOKin; // Expand any tuples in baseclasses[] for (size_t i = 0; i < cldec->baseclasses->length; ) { BaseClass *b = (*cldec->baseclasses)[i]; b->type = resolveBase(cldec, sc, scx, b->type); Type *tb = b->type->toBasetype(); if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; cldec->baseclasses->remove(i); size_t dim = Parameter::dim(tup->arguments); for (size_t j = 0; j < dim; j++) { Parameter *arg = Parameter::getNth(tup->arguments, j); b = new BaseClass(arg->type); cldec->baseclasses->insert(i + j, b); } } else i++; } if (cldec->baseok >= BASEOKdone) { //printf("%s already semantic analyzed, semanticRun = %d\n", cldec->toChars(), cldec->semanticRun); if (cldec->semanticRun >= PASSsemanticdone) return; goto Lancestorsdone; } // See if there's a base class as first in baseclasses[] if (cldec->baseclasses->length) { BaseClass *b = (*cldec->baseclasses)[0]; Type *tb = b->type->toBasetype(); TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL; if (!tc) { if (b->type != Type::terror) cldec->error("base type must be class or interface, not %s", b->type->toChars()); cldec->baseclasses->remove(0); goto L7; } if (tc->sym->isDeprecated()) { if (!cldec->isDeprecated()) { // Deriving from deprecated class makes this one deprecated too cldec->isdeprecated = true; tc->checkDeprecated(cldec->loc, sc); } } if (tc->sym->isInterfaceDeclaration()) goto L7; for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) { if (cdb == cldec) { cldec->error("circular inheritance"); cldec->baseclasses->remove(0); goto L7; } } /* Bugzilla 11034: Essentially, class inheritance hierarchy * and instance size of each classes are orthogonal information. * Therefore, even if tc->sym->sizeof == SIZEOKnone, * we need to set baseClass field for class covariance check. */ cldec->baseClass = tc->sym; b->sym = cldec->baseClass; if (tc->sym->baseok < BASEOKdone) resolveBase(cldec, sc, scx, tc->sym); // Try to resolve forward reference if (tc->sym->baseok < BASEOKdone) { //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); if (tc->sym->_scope) Module::addDeferredSemantic(tc->sym); cldec->baseok = BASEOKnone; } L7: ; } // Treat the remaining entries in baseclasses as interfaces // Check for errors, handle forward references for (size_t i = (cldec->baseClass ? 1 : 0); i < cldec->baseclasses->length; ) { BaseClass *b = (*cldec->baseclasses)[i]; Type *tb = b->type->toBasetype(); TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL; if (!tc || !tc->sym->isInterfaceDeclaration()) { if (b->type != Type::terror) cldec->error("base type must be interface, not %s", b->type->toChars()); cldec->baseclasses->remove(i); continue; } // Check for duplicate interfaces for (size_t j = (cldec->baseClass ? 1 : 0); j < i; j++) { BaseClass *b2 = (*cldec->baseclasses)[j]; if (b2->sym == tc->sym) { cldec->error("inherits from duplicate interface %s", b2->sym->toChars()); cldec->baseclasses->remove(i); continue; } } if (tc->sym->isDeprecated()) { if (!cldec->isDeprecated()) { // Deriving from deprecated class makes this one deprecated too cldec->isdeprecated = true; tc->checkDeprecated(cldec->loc, sc); } } b->sym = tc->sym; if (tc->sym->baseok < BASEOKdone) resolveBase(cldec, sc, scx, tc->sym); // Try to resolve forward reference if (tc->sym->baseok < BASEOKdone) { //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars()); if (tc->sym->_scope) Module::addDeferredSemantic(tc->sym); cldec->baseok = BASEOKnone; } i++; } if (cldec->baseok == BASEOKnone) { // Forward referencee of one or more bases, try again later cldec->_scope = scx ? scx : sc->copy(); cldec->_scope->setNoFree(); Module::addDeferredSemantic(cldec); //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars()); return; } cldec->baseok = BASEOKdone; // If no base class, and this is not an Object, use Object as base class if (!cldec->baseClass && cldec->ident != Id::Object && !cldec->isCPPclass()) { if (!ClassDeclaration::object || ClassDeclaration::object->errors) badObjectDotD(cldec); Type *t = ClassDeclaration::object->type; t = typeSemantic(t, cldec->loc, sc)->toBasetype(); if (t->ty == Terror) badObjectDotD(cldec); assert(t->ty == Tclass); TypeClass *tc = (TypeClass *)t; BaseClass *b = new BaseClass(tc); cldec->baseclasses->shift(b); cldec->baseClass = tc->sym; assert(!cldec->baseClass->isInterfaceDeclaration()); b->sym = cldec->baseClass; } if (cldec->baseClass) { if (cldec->baseClass->storage_class & STCfinal) cldec->error("cannot inherit from final class %s", cldec->baseClass->toChars()); // Inherit properties from base class if (cldec->baseClass->isCOMclass()) cldec->com = true; if (cldec->baseClass->isCPPclass()) cldec->classKind = ClassKind::cpp; if (cldec->baseClass->isscope) cldec->isscope = true; cldec->enclosing = cldec->baseClass->enclosing; cldec->storage_class |= cldec->baseClass->storage_class & STC_TYPECTOR; } cldec->interfaces.length = cldec->baseclasses->length - (cldec->baseClass ? 1 : 0); cldec->interfaces.ptr = cldec->baseclasses->tdata() + (cldec->baseClass ? 1 : 0); for (size_t i = 0; i < cldec->interfaces.length; i++) { BaseClass *b = cldec->interfaces.ptr[i]; // If this is an interface, and it derives from a COM interface, // then this is a COM interface too. if (b->sym->isCOMinterface()) cldec->com = true; if (cldec->isCPPclass() && !b->sym->isCPPinterface()) { error(cldec->loc, "C++ class `%s` cannot implement D interface `%s`", cldec->toPrettyChars(), b->sym->toPrettyChars()); } } interfaceSemantic(cldec); } Lancestorsdone: //printf("\tClassDeclaration::semantic(%s) baseok = %d\n", cldec->toChars(), cldec->baseok); if (!cldec->members) // if opaque declaration { cldec->semanticRun = PASSsemanticdone; return; } if (!cldec->symtab) { cldec->symtab = new DsymbolTable(); /* Bugzilla 12152: The semantic analysis of base classes should be finished * before the members semantic analysis of this class, in order to determine * vtbl in this class. However if a base class refers the member of this class, * it can be resolved as a normal forward reference. * Call addMember() and setScope() to make this class members visible from the base classes. */ for (size_t i = 0; i < cldec->members->length; i++) { Dsymbol *s = (*cldec->members)[i]; s->addMember(sc, cldec); } Scope *sc2 = cldec->newScope(sc); /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ for (size_t i = 0; i < cldec->members->length; i++) { Dsymbol *s = (*cldec->members)[i]; //printf("[%d] setScope %s %s, sc2 = %p\n", i, s->kind(), s->toChars(), sc2); s->setScope(sc2); } sc2->pop(); } for (size_t i = 0; i < cldec->baseclasses->length; i++) { BaseClass *b = (*cldec->baseclasses)[i]; Type *tb = b->type->toBasetype(); assert(tb->ty == Tclass); TypeClass *tc = (TypeClass *)tb; if (tc->sym->semanticRun < PASSsemanticdone) { // Forward referencee of one or more bases, try again later cldec->_scope = scx ? scx : sc->copy(); cldec->_scope->setNoFree(); if (tc->sym->_scope) Module::addDeferredSemantic(tc->sym); Module::addDeferredSemantic(cldec); //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars()); return; } } if (cldec->baseok == BASEOKdone) { cldec->baseok = BASEOKsemanticdone; // initialize vtbl if (cldec->baseClass) { if (cldec->isCPPclass() && cldec->baseClass->vtbl.length == 0) { cldec->error("C++ base class %s needs at least one virtual function", cldec->baseClass->toChars()); } // Copy vtbl[] from base class cldec->vtbl.setDim(cldec->baseClass->vtbl.length); memcpy(cldec->vtbl.tdata(), cldec->baseClass->vtbl.tdata(), sizeof(void *) * cldec->vtbl.length); cldec->vthis = cldec->baseClass->vthis; } else { // No base class, so this is the root of the class hierarchy cldec->vtbl.setDim(0); if (cldec->vtblOffset()) cldec->vtbl.push(cldec); // leave room for classinfo as first member } /* If this is a nested class, add the hidden 'this' * member which is a pointer to the enclosing scope. */ if (cldec->vthis) // if inheriting from nested class { // Use the base class's 'this' member if (cldec->storage_class & STCstatic) cldec->error("static class cannot inherit from nested class %s", cldec->baseClass->toChars()); if (cldec->toParent2() != cldec->baseClass->toParent2() && (!cldec->toParent2() || !cldec->baseClass->toParent2()->getType() || !cldec->baseClass->toParent2()->getType()->isBaseOf(cldec->toParent2()->getType(), NULL))) { if (cldec->toParent2()) { cldec->error("is nested within %s, but super class %s is nested within %s", cldec->toParent2()->toChars(), cldec->baseClass->toChars(), cldec->baseClass->toParent2()->toChars()); } else { cldec->error("is not nested, but super class %s is nested within %s", cldec->baseClass->toChars(), cldec->baseClass->toParent2()->toChars()); } cldec->enclosing = NULL; } } else cldec->makeNested(); } Scope *sc2 = cldec->newScope(sc); for (size_t i = 0; i < cldec->members->length; i++) { Dsymbol *s = (*cldec->members)[i]; s->importAll(sc2); } // Note that members.length can grow due to tuple expansion during semantic() for (size_t i = 0; i < cldec->members->length; i++) { Dsymbol *s = (*cldec->members)[i]; dsymbolSemantic(s, sc2); } if (!cldec->determineFields()) { assert(cldec->type == Type::terror); sc2->pop(); return; } /* Following special member functions creation needs semantic analysis * completion of sub-structs in each field types. */ for (size_t i = 0; i < cldec->fields.length; i++) { VarDeclaration *v = cldec->fields[i]; Type *tb = v->type->baseElemOf(); if (tb->ty != Tstruct) continue; StructDeclaration *sd = ((TypeStruct *)tb)->sym; if (sd->semanticRun >= PASSsemanticdone) continue; sc2->pop(); cldec->_scope = scx ? scx : sc->copy(); cldec->_scope->setNoFree(); Module::addDeferredSemantic(cldec); //printf("\tdeferring %s\n", cldec->toChars()); return; } /* Look for special member functions. * They must be in this class, not in a base class. */ // Can be in base class cldec->aggNew = (NewDeclaration *)cldec->search(Loc(), Id::classNew); cldec->aggDelete = (DeleteDeclaration *)cldec->search(Loc(), Id::classDelete); // Look for the constructor cldec->ctor = cldec->searchCtor(); if (!cldec->ctor && cldec->noDefaultCtor) { // A class object is always created by constructor, so this check is legitimate. for (size_t i = 0; i < cldec->fields.length; i++) { VarDeclaration *v = cldec->fields[i]; if (v->storage_class & STCnodefaultctor) error(v->loc, "field %s must be initialized in constructor", v->toChars()); } } // If this class has no constructor, but base class has a default // ctor, create a constructor: // this() { } if (!cldec->ctor && cldec->baseClass && cldec->baseClass->ctor) { FuncDeclaration *fd = resolveFuncCall(cldec->loc, sc2, cldec->baseClass->ctor, NULL, cldec->type, NULL, 1); if (!fd) // try shared base ctor instead fd = resolveFuncCall(cldec->loc, sc2, cldec->baseClass->ctor, NULL, cldec->type->sharedOf(), NULL, 1); if (fd && !fd->errors) { //printf("Creating default this(){} for class %s\n", cldec->toChars()); TypeFunction *btf = fd->type->toTypeFunction(); TypeFunction *tf = new TypeFunction(ParameterList(), NULL, LINKd, fd->storage_class); tf->mod = btf->mod; tf->purity = btf->purity; tf->isnothrow = btf->isnothrow; tf->isnogc = btf->isnogc; tf->trust = btf->trust; CtorDeclaration *ctor = new CtorDeclaration(cldec->loc, Loc(), 0, tf); ctor->fbody = new CompoundStatement(Loc(), new Statements()); cldec->members->push(ctor); ctor->addMember(sc, cldec); dsymbolSemantic(ctor, sc2); cldec->ctor = ctor; cldec->defaultCtor = ctor; } else { cldec->error("cannot implicitly generate a default ctor when base class %s is missing a default ctor", cldec->baseClass->toPrettyChars()); } } cldec->dtor = buildDtor(cldec, sc2); if (FuncDeclaration *f = hasIdentityOpAssign(cldec, sc2)) { if (!(f->storage_class & STCdisable)) cldec->error(f->loc, "identity assignment operator overload is illegal"); } cldec->inv = buildInv(cldec, sc2); Module::dprogress++; cldec->semanticRun = PASSsemanticdone; //printf("-ClassDeclaration.semantic(%s), type = %p\n", cldec->toChars(), cldec->type); //members.print(); sc2->pop(); if (cldec->type->ty == Tclass && ((TypeClass *)cldec->type)->sym != cldec) { // https://issues.dlang.org/show_bug.cgi?id=17492 ClassDeclaration *cd = ((TypeClass *)cldec->type)->sym; cldec->error("already exists at %s. Perhaps in another function with the same name?", cd->loc.toChars()); } if (global.errors != errors) { // The type is no good. cldec->type = Type::terror; cldec->errors = true; if (cldec->deferred) cldec->deferred->errors = true; } // Verify fields of a synchronized class are not public if (cldec->storage_class & STCsynchronized) { for (size_t i = 0; i < cldec->fields.length; i++) { VarDeclaration *vd = cldec->fields[i]; if (!vd->isThisDeclaration() && !vd->prot().isMoreRestrictiveThan(Prot(Prot::public_))) { vd->error("Field members of a synchronized class cannot be %s", protectionToChars(vd->prot().kind)); } } } if (cldec->deferred && !global.gag) { semantic2(cldec->deferred, sc); semantic3(cldec->deferred, sc); } //printf("-ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec); } void visit(InterfaceDeclaration *idec) { //printf("InterfaceDeclaration::semantic(%s), type = %p\n", idec->toChars(), idec->type); if (idec->semanticRun >= PASSsemanticdone) return; unsigned errors = global.errors; //printf("+InterfaceDeclaration.semantic(%s), type = %p\n", idec->toChars(), idec->type); Scope *scx = NULL; if (idec->_scope) { sc = idec->_scope; scx = idec->_scope; // save so we don't make redundant copies idec->_scope = NULL; } if (!idec->parent) { assert(sc->parent && sc->func); idec->parent = sc->parent; } assert(idec->parent && !idec->isAnonymous()); if (idec->errors) idec->type = Type::terror; idec->type = typeSemantic(idec->type, idec->loc, sc); if (idec->type->ty == Tclass && ((TypeClass *)idec->type)->sym != idec) { TemplateInstance *ti = ((TypeClass *)idec->type)->sym->isInstantiated(); if (ti && isError(ti)) ((TypeClass *)idec->type)->sym = idec; } // Ungag errors when not speculative Ungag ungag = idec->ungagSpeculative(); if (idec->semanticRun == PASSinit) { idec->protection = sc->protection; idec->storage_class |= sc->stc; if (idec->storage_class & STCdeprecated) idec->isdeprecated = true; idec->userAttribDecl = sc->userAttribDecl; } else if (idec->symtab) { if (idec->sizeok == SIZEOKdone || !scx) { idec->semanticRun = PASSsemanticdone; return; } } idec->semanticRun = PASSsemantic; if (idec->baseok < BASEOKdone) { idec->baseok = BASEOKin; // Expand any tuples in baseclasses[] for (size_t i = 0; i < idec->baseclasses->length; ) { BaseClass *b = (*idec->baseclasses)[i]; b->type = resolveBase(idec, sc, scx, b->type); Type *tb = b->type->toBasetype(); if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; idec->baseclasses->remove(i); size_t dim = Parameter::dim(tup->arguments); for (size_t j = 0; j < dim; j++) { Parameter *arg = Parameter::getNth(tup->arguments, j); b = new BaseClass(arg->type); idec->baseclasses->insert(i + j, b); } } else i++; } if (idec->baseok >= BASEOKdone) { //printf("%s already semantic analyzed, semanticRun = %d\n", idec->toChars(), idec->semanticRun); if (idec->semanticRun >= PASSsemanticdone) return; goto Lancestorsdone; } if (!idec->baseclasses->length && sc->linkage == LINKcpp) idec->classKind = ClassKind::cpp; if (sc->linkage == LINKobjc) objc()->setObjc(idec); // Check for errors, handle forward references for (size_t i = 0; i < idec->baseclasses->length; ) { BaseClass *b = (*idec->baseclasses)[i]; Type *tb = b->type->toBasetype(); TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL; if (!tc || !tc->sym->isInterfaceDeclaration()) { if (b->type != Type::terror) idec->error("base type must be interface, not %s", b->type->toChars()); idec->baseclasses->remove(i); continue; } // Check for duplicate interfaces for (size_t j = 0; j < i; j++) { BaseClass *b2 = (*idec->baseclasses)[j]; if (b2->sym == tc->sym) { idec->error("inherits from duplicate interface %s", b2->sym->toChars()); idec->baseclasses->remove(i); continue; } } if (tc->sym == idec || idec->isBaseOf2(tc->sym)) { idec->error("circular inheritance of interface"); idec->baseclasses->remove(i); continue; } if (tc->sym->isDeprecated()) { if (!idec->isDeprecated()) { // Deriving from deprecated class makes this one deprecated too idec->isdeprecated = true; tc->checkDeprecated(idec->loc, sc); } } b->sym = tc->sym; if (tc->sym->baseok < BASEOKdone) resolveBase(idec, sc, scx, tc->sym); // Try to resolve forward reference if (tc->sym->baseok < BASEOKdone) { //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars()); if (tc->sym->_scope) Module::addDeferredSemantic(tc->sym); idec->baseok = BASEOKnone; } i++; } if (idec->baseok == BASEOKnone) { // Forward referencee of one or more bases, try again later idec->_scope = scx ? scx : sc->copy(); idec->_scope->setNoFree(); Module::addDeferredSemantic(idec); return; } idec->baseok = BASEOKdone; idec->interfaces.length = idec->baseclasses->length; idec->interfaces.ptr = idec->baseclasses->tdata(); for (size_t i = 0; i < idec->interfaces.length; i++) { BaseClass *b = idec->interfaces.ptr[i]; // If this is an interface, and it derives from a COM interface, // then this is a COM interface too. if (b->sym->isCOMinterface()) idec->com = true; if (b->sym->isCPPinterface()) idec->classKind = ClassKind::cpp; } interfaceSemantic(idec); } Lancestorsdone: if (!idec->members) // if opaque declaration { idec->semanticRun = PASSsemanticdone; return; } if (!idec->symtab) idec->symtab = new DsymbolTable(); for (size_t i = 0; i < idec->baseclasses->length; i++) { BaseClass *b = (*idec->baseclasses)[i]; Type *tb = b->type->toBasetype(); assert(tb->ty == Tclass); TypeClass *tc = (TypeClass *)tb; if (tc->sym->semanticRun < PASSsemanticdone) { // Forward referencee of one or more bases, try again later idec->_scope = scx ? scx : sc->copy(); idec->_scope->setNoFree(); if (tc->sym->_scope) Module::addDeferredSemantic(tc->sym); Module::addDeferredSemantic(idec); return; } } if (idec->baseok == BASEOKdone) { idec->baseok = BASEOKsemanticdone; // initialize vtbl if (idec->vtblOffset()) idec->vtbl.push(idec); // leave room at vtbl[0] for classinfo // Cat together the vtbl[]'s from base cldec->interfaces for (size_t i = 0; i < idec->interfaces.length; i++) { BaseClass *b = idec->interfaces.ptr[i]; // Skip if b has already appeared for (size_t k = 0; k < i; k++) { if (b == idec->interfaces.ptr[k]) goto Lcontinue; } // Copy vtbl[] from base class if (b->sym->vtblOffset()) { size_t d = b->sym->vtbl.length; if (d > 1) { idec->vtbl.reserve(d - 1); for (size_t j = 1; j < d; j++) idec->vtbl.push(b->sym->vtbl[j]); } } else { idec->vtbl.append(&b->sym->vtbl); } Lcontinue: ; } } for (size_t i = 0; i < idec->members->length; i++) { Dsymbol *s = (*idec->members)[i]; s->addMember(sc, idec); } Scope *sc2 = idec->newScope(sc); /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ for (size_t i = 0; i < idec->members->length; i++) { Dsymbol *s = (*idec->members)[i]; //printf("setScope %s %s\n", s->kind(), s->toChars()); s->setScope(sc2); } for (size_t i = 0; i < idec->members->length; i++) { Dsymbol *s = (*idec->members)[i]; s->importAll(sc2); } for (size_t i = 0; i < idec->members->length; i++) { Dsymbol *s = (*idec->members)[i]; dsymbolSemantic(s, sc2); } Module::dprogress++; idec->semanticRun = PASSsemanticdone; //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", idec->toChars(), idec->type); //members->print(); sc2->pop(); if (global.errors != errors) { // The type is no good. idec->type = Type::terror; } assert(idec->type->ty != Tclass || ((TypeClass *)idec->type)->sym == idec); } }; /****************************************************** * Do template instance semantic for isAliasSeq templates. * This is a greatly simplified version of TemplateInstance::semantic(). */ static void aliasSeqInstanceSemantic(TemplateInstance *tempinst, Scope *sc, TemplateDeclaration *tempdecl) { //printf("[%s] aliasSeqInstanceSemantic('%s')\n", tempinst->loc.toChars(), tempinst->toChars()); Scope *paramscope = sc->push(); paramscope->stc = 0; paramscope->protection = Prot(Prot::public_); TemplateTupleParameter *ttp = (*tempdecl->parameters)[0]->isTemplateTupleParameter(); Tuple *va = isTuple(tempinst->tdtypes[0]); Declaration *d = new TupleDeclaration(tempinst->loc, ttp->ident, &va->objects); d->storage_class |= STCtemplateparameter; dsymbolSemantic(d, sc); paramscope->pop(); tempinst->aliasdecl = d; tempinst->semanticRun = PASSsemanticdone; } /****************************************************** * Do template instance semantic for isAlias templates. * This is a greatly simplified version of TemplateInstance::semantic(). */ static void aliasInstanceSemantic(TemplateInstance *tempinst, Scope *sc, TemplateDeclaration *tempdecl) { //printf("[%s] aliasInstanceSemantic('%s')\n", tempinst->loc.toChars(), tempinst->toChars()); Scope *paramscope = sc->push(); paramscope->stc = 0; paramscope->protection = Prot(Prot::public_); TemplateTypeParameter *ttp = (*tempdecl->parameters)[0]->isTemplateTypeParameter(); Type *ta = isType(tempinst->tdtypes[0]); AliasDeclaration *ad = tempdecl->onemember->isAliasDeclaration(); // Note: qualifiers can be in both 'ad.type.mod' and 'ad.storage_class' Declaration *d = new AliasDeclaration(tempinst->loc, ttp->ident, ta->addMod(ad->type->mod)); d->storage_class |= STCtemplateparameter | ad->storage_class; dsymbolSemantic(d, sc); paramscope->pop(); tempinst->aliasdecl = d; tempinst->semanticRun = PASSsemanticdone; } void templateInstanceSemantic(TemplateInstance *tempinst, Scope *sc, Expressions *fargs) { //printf("[%s] TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst->loc.toChars(), tempinst->toChars(), tempinst, global.gag, sc); if (tempinst->inst) // if semantic() was already run { return; } if (tempinst->semanticRun != PASSinit) { Ungag ungag(global.gag); if (!tempinst->gagged) global.gag = 0; tempinst->error(tempinst->loc, "recursive template expansion"); if (tempinst->gagged) tempinst->semanticRun = PASSinit; else tempinst->inst = tempinst; tempinst->errors = true; return; } // Get the enclosing template instance from the scope tinst tempinst->tinst = sc->tinst; // Get the instantiating module from the scope minst tempinst->minst = sc->minst; // Bugzilla 10920: If the enclosing function is non-root symbol, // this instance should be speculative. if (!tempinst->tinst && sc->func && sc->func->inNonRoot()) { tempinst->minst = NULL; } tempinst->gagged = (global.gag > 0); tempinst->semanticRun = PASSsemantic; /* Find template declaration first, * then run semantic on each argument (place results in tiargs[]), * last find most specialized template from overload list/set. */ if (!tempinst->findTempDecl(sc, NULL) || !tempinst->semanticTiargs(sc) || !tempinst->findBestMatch(sc, fargs)) { Lerror: if (tempinst->gagged) { // Bugzilla 13220: Rollback status for later semantic re-running. tempinst->semanticRun = PASSinit; } else tempinst->inst = tempinst; tempinst->errors = true; return; } TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration(); assert(tempdecl); // If tempdecl is a mixin, disallow it if (tempdecl->ismixin) { tempinst->error("mixin templates are not regular templates"); goto Lerror; } tempinst->hasNestedArgs(tempinst->tiargs, tempdecl->isstatic); if (tempinst->errors) goto Lerror; /* Greatly simplified semantic processing for AliasSeq templates */ if (tempdecl->isTrivialAliasSeq) { tempinst->inst = tempinst; return aliasSeqInstanceSemantic(tempinst, sc, tempdecl); } /* Greatly simplified semantic processing for Alias templates */ else if (tempdecl->isTrivialAlias) { tempinst->inst = tempinst; return aliasInstanceSemantic(tempinst, sc, tempdecl); } /* See if there is an existing TemplateInstantiation that already * implements the typeargs. If so, just refer to that one instead. */ tempinst->inst = tempdecl->findExistingInstance(tempinst, fargs); TemplateInstance *errinst = NULL; if (!tempinst->inst) { // So, we need to implement 'this' instance. } else if (tempinst->inst->gagged && !tempinst->gagged && tempinst->inst->errors) { // If the first instantiation had failed, re-run semantic, // so that error messages are shown. errinst = tempinst->inst; } else { // It's a match tempinst->parent = tempinst->inst->parent; tempinst->errors = tempinst->inst->errors; // If both this and the previous instantiation were gagged, // use the number of errors that happened last time. global.errors += tempinst->errors; global.gaggedErrors += tempinst->errors; // If the first instantiation was gagged, but this is not: if (tempinst->inst->gagged) { // It had succeeded, mark it is a non-gagged instantiation, // and reuse it. tempinst->inst->gagged = tempinst->gagged; } tempinst->tnext = tempinst->inst->tnext; tempinst->inst->tnext = tempinst; /* A module can have explicit template instance and its alias * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`). * If the first instantiation 'inst' had happened in non-root module, * compiler can assume that its instantiated code would be included * in the separately compiled obj/lib file (e.g. phobos.lib). * * However, if 'this' second instantiation happened in root module, * compiler might need to invoke its codegen (Bugzilla 2500 & 2644). * But whole import graph is not determined until all semantic pass finished, * so 'inst' should conservatively finish the semantic3 pass for the codegen. */ if (tempinst->minst && tempinst->minst->isRoot() && !(tempinst->inst->minst && tempinst->inst->minst->isRoot())) { /* Swap the position of 'inst' and 'this' in the instantiation graph. * Then, the primary instance `inst` will be changed to a root instance, * along with all members of `inst` having their scopes updated. * * Before: * non-root -> A!() -> B!()[inst] -> C!() { members[non-root] } * | * root -> D!() -> B!()[this] * * After: * non-root -> A!() -> B!()[this] * | * root -> D!() -> B!()[inst] -> C!() { members[root] } */ Module *mi = tempinst->minst; TemplateInstance *ti = tempinst->tinst; tempinst->minst = tempinst->inst->minst; tempinst->tinst = tempinst->inst->tinst; tempinst->inst->minst = mi; tempinst->inst->tinst = ti; /* https://issues.dlang.org/show_bug.cgi?id=21299 `minst` has been updated on the primary instance `inst` so it is now coming from a root module, however all Dsymbol `inst.members` of the instance still have their `_scope.minst` pointing at the original non-root module. We must now propagate `minst` to all members so that forward referenced dependencies that get instantiated will also be appended to the root module, otherwise there will be undefined references at link-time. */ class InstMemberWalker : public Visitor { public: TemplateInstance *inst; InstMemberWalker(TemplateInstance *inst) : inst(inst) { } void visit(Dsymbol *d) { if (d->_scope) d->_scope->minst = inst->minst; } void visit(ScopeDsymbol *sds) { if (!sds->members) return; for (size_t i = 0; i < sds->members->length; i++) { Dsymbol *s = (*sds->members)[i]; s->accept(this); } visit((Dsymbol *)sds); } void visit(AttribDeclaration *ad) { Dsymbols *d = ad->include(NULL); if (!d) return; for (size_t i = 0; i < d->length; i++) { Dsymbol *s = (*d)[i]; s->accept(this); } visit((Dsymbol *)ad); } void visit(ConditionalDeclaration *cd) { if (cd->condition->inc) visit((AttribDeclaration *)cd); else visit((Dsymbol *)cd); } }; InstMemberWalker v(tempinst->inst); tempinst->inst->accept(&v); if (tempinst->minst) // if inst was not speculative { /* Add 'inst' once again to the root module members[], then the * instance members will get codegen chances. */ tempinst->inst->appendToModuleMember(); } } return; } unsigned errorsave = global.errors; tempinst->inst = tempinst; tempinst->parent = tempinst->enclosing ? tempinst->enclosing : tempdecl->parent; //printf("parent = '%s'\n", tempinst->parent->kind()); TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(tempinst); //getIdent(); // Store the place we added it to in target_symbol_list(_idx) so we can // remove it later if we encounter an error. Dsymbols *target_symbol_list = tempinst->appendToModuleMember(); size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list->length - 1 : 0; // Copy the syntax trees from the TemplateDeclaration tempinst->members = Dsymbol::arraySyntaxCopy(tempdecl->members); // resolve TemplateThisParameter for (size_t i = 0; i < tempdecl->parameters->length; i++) { if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL) continue; Type *t = isType((*tempinst->tiargs)[i]); assert(t); if (StorageClass stc = ModToStc(t->mod)) { //printf("t = %s, stc = x%llx\n", t->toChars(), stc); Dsymbols *s = new Dsymbols(); s->push(new StorageClassDeclaration(stc, tempinst->members)); tempinst->members = s; } break; } // Create our own scope for the template parameters Scope *scope = tempdecl->_scope; if (tempdecl->semanticRun == PASSinit) { tempinst->error("template instantiation %s forward references template declaration %s", tempinst->toChars(), tempdecl->toChars()); return; } tempinst->argsym = new ScopeDsymbol(); tempinst->argsym->parent = scope->parent; scope = scope->push(tempinst->argsym); scope->tinst = tempinst; scope->minst = tempinst->minst; //scope->stc = 0; // Declare each template parameter as an alias for the argument type Scope *paramscope = scope->push(); paramscope->stc = 0; paramscope->protection = Prot(Prot::public_); // Bugzilla 14169: template parameters should be public tempinst->declareParameters(paramscope); paramscope->pop(); // Add members of template instance to template instance symbol table // tempinst->parent = scope->scopesym; tempinst->symtab = new DsymbolTable(); for (size_t i = 0; i < tempinst->members->length; i++) { Dsymbol *s = (*tempinst->members)[i]; s->addMember(scope, tempinst); } /* See if there is only one member of template instance, and that * member has the same name as the template instance. * If so, this template instance becomes an alias for that member. */ //printf("members->length = %d\n", tempinst->members->length); if (tempinst->members->length) { Dsymbol *s; if (Dsymbol::oneMembers(tempinst->members, &s, tempdecl->ident) && s) { //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars()); //printf("setting aliasdecl\n"); tempinst->aliasdecl = s; } } /* If function template declaration */ if (fargs && tempinst->aliasdecl) { FuncDeclaration *fd = tempinst->aliasdecl->isFuncDeclaration(); if (fd) { /* Transmit fargs to type so that TypeFunction::semantic() can * resolve any "auto ref" storage classes. */ TypeFunction *tf = (TypeFunction *)fd->type; if (tf && tf->ty == Tfunction) tf->fargs = fargs; } } // Do semantic() analysis on template instance members Scope *sc2; sc2 = scope->push(tempinst); //printf("enclosing = %d, sc->parent = %s\n", tempinst->enclosing, sc->parent->toChars()); sc2->parent = tempinst; sc2->tinst = tempinst; sc2->minst = tempinst->minst; tempinst->tryExpandMembers(sc2); tempinst->semanticRun = PASSsemanticdone; /* ConditionalDeclaration may introduce eponymous declaration, * so we should find it once again after semantic. */ if (tempinst->members->length) { Dsymbol *s; if (Dsymbol::oneMembers(tempinst->members, &s, tempdecl->ident) && s) { if (!tempinst->aliasdecl || tempinst->aliasdecl != s) { //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars()); //printf("setting aliasdecl 2\n"); tempinst->aliasdecl = s; } } } if (global.errors != errorsave) goto Laftersemantic; /* If any of the instantiation members didn't get semantic() run * on them due to forward references, we cannot run semantic2() * or semantic3() yet. */ { bool found_deferred_ad = false; for (size_t i = 0; i < Module::deferred.length; i++) { Dsymbol *sd = Module::deferred[i]; AggregateDeclaration *ad = sd->isAggregateDeclaration(); if (ad && ad->parent && ad->parent->isTemplateInstance()) { //printf("deferred template aggregate: %s %s\n", // sd->parent->toChars(), sd->toChars()); found_deferred_ad = true; if (ad->parent == tempinst) { ad->deferred = tempinst; break; } } } if (found_deferred_ad || Module::deferred.length) goto Laftersemantic; } /* The problem is when to parse the initializer for a variable. * Perhaps VarDeclaration::semantic() should do it like it does * for initializers inside a function. */ //if (sc->parent->isFuncDeclaration()) { /* BUG 782: this has problems if the classes this depends on * are forward referenced. Find a way to defer semantic() * on this template. */ semantic2(tempinst, sc2); } if (global.errors != errorsave) goto Laftersemantic; if ((sc->func || (sc->flags & SCOPEfullinst)) && !tempinst->tinst) { /* If a template is instantiated inside function, the whole instantiation * should be done at that position. But, immediate running semantic3 of * dependent templates may cause unresolved forward reference (Bugzilla 9050). * To avoid the issue, don't run semantic3 until semantic and semantic2 done. */ TemplateInstances deferred; tempinst->deferred = &deferred; //printf("Run semantic3 on %s\n", tempinst->toChars()); tempinst->trySemantic3(sc2); for (size_t i = 0; i < deferred.length; i++) { //printf("+ run deferred semantic3 on %s\n", deferred[i]->toChars()); semantic3(deferred[i], NULL); } tempinst->deferred = NULL; } else if (tempinst->tinst) { bool doSemantic3 = false; if (sc->func && tempinst->aliasdecl && tempinst->aliasdecl->toAlias()->isFuncDeclaration()) { /* Template function instantiation should run semantic3 immediately * for attribute inference. */ tempinst->trySemantic3(sc2); } else if (sc->func) { /* A lambda function in template arguments might capture the * instantiated scope context. For the correct context inference, * all instantiated functions should run the semantic3 immediately. * See also compilable/test14973.d */ for (size_t i = 0; i < tempinst->tdtypes.length; i++) { RootObject *oarg = tempinst->tdtypes[i]; Dsymbol *s = getDsymbol(oarg); if (!s) continue; if (TemplateDeclaration *td = s->isTemplateDeclaration()) { if (!td->literal) continue; assert(td->members && td->members->length == 1); s = (*td->members)[0]; } if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) { if (fld->tok == TOKreserved) { doSemantic3 = true; break; } } } //printf("[%s] %s doSemantic3 = %d\n", tempinst->loc.toChars(), tempinst->toChars(), doSemantic3); } if (doSemantic3) tempinst->trySemantic3(sc2); TemplateInstance *ti = tempinst->tinst; int nest = 0; while (ti && !ti->deferred && ti->tinst) { ti = ti->tinst; if (++nest > global.recursionLimit) { global.gag = 0; // ensure error message gets printed tempinst->error("recursive expansion"); fatal(); } } if (ti && ti->deferred) { //printf("deferred semantic3 of %p %s, ti = %s, ti->deferred = %p\n", tempinst, tempinst->toChars(), ti->toChars()); for (size_t i = 0; ; i++) { if (i == ti->deferred->length) { ti->deferred->push(tempinst); break; } if ((*ti->deferred)[i] == tempinst) break; } } } if (tempinst->aliasdecl) { /* Bugzilla 13816: AliasDeclaration tries to resolve forward reference * twice (See inuse check in AliasDeclaration::toAlias()). It's * necessary to resolve mutual references of instantiated symbols, but * it will left a true recursive alias in tuple declaration - an * AliasDeclaration A refers TupleDeclaration B, and B contains A * in its elements. To correctly make it an error, we strictly need to * resolve the alias of eponymous member. */ tempinst->aliasdecl = tempinst->aliasdecl->toAlias2(); } Laftersemantic: sc2->pop(); scope->pop(); // Give additional context info if error occurred during instantiation if (global.errors != errorsave) { if (!tempinst->errors) { if (!tempdecl->literal) tempinst->error(tempinst->loc, "error instantiating"); if (tempinst->tinst) tempinst->tinst->printInstantiationTrace(); } tempinst->errors = true; if (tempinst->gagged) { // Errors are gagged, so remove the template instance from the // instance/symbol lists we added it to and reset our state to // finish clean and so we can try to instantiate it again later // (see bugzilla 4302 and 6602). tempdecl->removeInstance(tempdecl_instance_idx); if (target_symbol_list) { // Because we added 'this' in the last position above, we // should be able to remove it without messing other indices up. assert((*target_symbol_list)[target_symbol_list_idx] == tempinst); target_symbol_list->remove(target_symbol_list_idx); tempinst->memberOf = NULL; // no longer a member } tempinst->semanticRun = PASSinit; tempinst->inst = NULL; tempinst->symtab = NULL; } } else if (errinst) { /* Bugzilla 14541: If the previous gagged instance had failed by * circular references, currrent "error reproduction instantiation" * might succeed, because of the difference of instantiated context. * On such case, the cached error instance needs to be overridden by the * succeeded instance. */ //printf("replaceInstance()\n"); TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)tempdecl->instances, (void *)tempinst->hash); assert(tinstances); for (size_t i = 0; i < tinstances->length; i++) { TemplateInstance *ti = (*tinstances)[i]; if (ti == errinst) { (*tinstances)[i] = tempinst; // override break; } } } } // function used to perform semantic on AliasDeclaration void aliasSemantic(AliasDeclaration *ds, Scope *sc) { //printf("AliasDeclaration::semantic() %s\n", ds->toChars()); // as AliasDeclaration::semantic, in case we're called first. // see https://issues.dlang.org/show_bug.cgi?id=21001 ds->storage_class |= sc->stc & STCdeprecated; ds->protection = sc->protection; ds->userAttribDecl = sc->userAttribDecl; // TypeTraits needs to know if it's located in an AliasDeclaration const unsigned oldflags = sc->flags; sc->flags |= SCOPEalias; if (ds->aliassym) { FuncDeclaration *fd = ds->aliassym->isFuncLiteralDeclaration(); TemplateDeclaration *td = ds->aliassym->isTemplateDeclaration(); if (fd || (td && td->literal)) { if (fd && fd->semanticRun >= PASSsemanticdone) { sc->flags = oldflags; return; } Expression *e = new FuncExp(ds->loc, ds->aliassym); e = expressionSemantic(e, sc); if (e->op == TOKfunction) { FuncExp *fe = (FuncExp *)e; ds->aliassym = fe->td ? (Dsymbol *)fe->td : fe->fd; } else { ds->aliassym = NULL; ds->type = Type::terror; } sc->flags = oldflags; return; } if (ds->aliassym->isTemplateInstance()) dsymbolSemantic(ds->aliassym, sc); sc->flags = oldflags; return; } ds->inuse = 1; // Given: // alias foo.bar.abc def; // it is not knowable from the syntax whether this is an alias // for a type or an alias for a symbol. It is up to the semantic() // pass to distinguish. // If it is a type, then type is set and getType() will return that // type. If it is a symbol, then aliassym is set and type is NULL - // toAlias() will return aliasssym. unsigned int errors = global.errors; Type *oldtype = ds->type; // Ungag errors when not instantiated DeclDefs scope alias Ungag ungag(global.gag); //printf("%s parent = %s, gag = %d, instantiated = %d\n", ds->toChars(), ds->parent, global.gag, ds->isInstantiated()); if (ds->parent && global.gag && !ds->isInstantiated() && !ds->toParent2()->isFuncDeclaration()) { //printf("%s type = %s\n", ds->toPrettyChars(), ds->type->toChars()); global.gag = 0; } /* This section is needed because Type::resolve() will: * const x = 3; * alias y = x; * try to convert identifier x to 3. */ Dsymbol *s = ds->type->toDsymbol(sc); if (errors != global.errors) { s = NULL; ds->type = Type::terror; } if (s && s == ds) { ds->error("cannot resolve"); s = NULL; ds->type = Type::terror; } if (!s || !s->isEnumMember()) { Type *t; Expression *e; Scope *sc2 = sc; if (ds->storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCdisable)) { // For 'ref' to be attached to function types, and picked // up by Type::resolve(), it has to go into sc. sc2 = sc->push(); sc2->stc |= ds->storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCshared | STCdisable); } ds->type = ds->type->addSTC(ds->storage_class); ds->type->resolve(ds->loc, sc2, &e, &t, &s); if (sc2 != sc) sc2->pop(); if (e) // Try to convert Expression to Dsymbol { s = getDsymbol(e); if (!s) { if (e->op != TOKerror) ds->error("cannot alias an expression %s", e->toChars()); t = Type::terror; } } ds->type = t; } if (s == ds) { assert(global.errors); ds->type = Type::terror; s = NULL; } if (!s) // it's a type alias { //printf("alias %s resolved to type %s\n", ds->toChars(), ds->type->toChars()); ds->type = typeSemantic(ds->type, ds->loc, sc); ds->aliassym = NULL; } else // it's a symbolic alias { //printf("alias %s resolved to %s %s\n", ds->toChars(), s->kind(), s->toChars()); ds->type = NULL; ds->aliassym = s; } if (global.gag && errors != global.errors) { ds->type = oldtype; ds->aliassym = NULL; } ds->inuse = 0; ds->semanticRun = PASSsemanticdone; if (Dsymbol *sx = ds->overnext) { ds->overnext = NULL; if (!ds->overloadInsert(sx)) ScopeDsymbol::multiplyDefined(Loc(), sx, ds); } sc->flags = oldflags; } /************************************* * Does semantic analysis on the public face of declarations. */ void dsymbolSemantic(Dsymbol *dsym, Scope *sc) { DsymbolSemanticVisitor v(sc); dsym->accept(&v); }