diff options
Diffstat (limited to 'gcc/d/dmd/dsymbolsem.c')
-rw-r--r-- | gcc/d/dmd/dsymbolsem.c | 5620 |
1 files changed, 0 insertions, 5620 deletions
diff --git a/gcc/d/dmd/dsymbolsem.c b/gcc/d/dmd/dsymbolsem.c deleted file mode 100644 index 7a44ed2c41d..00000000000 --- a/gcc/d/dmd/dsymbolsem.c +++ /dev/null @@ -1,5620 +0,0 @@ - -/* 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); -} |