diff options
Diffstat (limited to 'gcc/d/dmd/attrib.c')
-rw-r--r-- | gcc/d/dmd/attrib.c | 1320 |
1 files changed, 0 insertions, 1320 deletions
diff --git a/gcc/d/dmd/attrib.c b/gcc/d/dmd/attrib.c deleted file mode 100644 index a808b8a..0000000 --- a/gcc/d/dmd/attrib.c +++ /dev/null @@ -1,1320 +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 - * https://github.com/D-Programming-Language/dmd/blob/master/src/attrib.c - */ - -#include "root/dsystem.h" // memcmp() -#include "root/rmem.h" - -#include "mars.h" -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "cond.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "module.h" -#include "parse.h" -#include "target.h" -#include "template.h" -#include "utf.h" -#include "mtype.h" - -bool definitelyValueParameter(Expression *e); -Dsymbols *makeTupleForeachStaticDecl(Scope *sc, ForeachStatement *fs, Dsymbols *dbody, bool needExpansion); - -/********************************* AttribDeclaration ****************************/ - -AttribDeclaration::AttribDeclaration(Dsymbols *decl) - : Dsymbol() -{ - this->decl = decl; -} - -Dsymbols *AttribDeclaration::include(Scope *) -{ - if (errors) - return NULL; - - return decl; -} - -int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param) -{ - Dsymbols *d = include(_scope); - - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -/**************************************** - * Create a new scope if one or more given attributes - * are different from the sc's. - * If the returned scope != sc, the caller should pop - * the scope after it used. - */ -Scope *AttribDeclaration::createNewScope(Scope *sc, - StorageClass stc, LINK linkage, CPPMANGLE cppmangle, Prot protection, - int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining) -{ - Scope *sc2 = sc; - if (stc != sc->stc || - linkage != sc->linkage || - cppmangle != sc->cppmangle || - explicitProtection != sc->explicitProtection || - !(protection == sc->protection) || - aligndecl != sc->aligndecl || - inlining != sc->inlining) - { - // create new one for changes - sc2 = sc->copy(); - sc2->stc = stc; - sc2->linkage = linkage; - sc2->cppmangle = cppmangle; - sc2->protection = protection; - sc2->explicitProtection = explicitProtection; - sc2->aligndecl = aligndecl; - sc2->inlining = inlining; - } - return sc2; -} - -/**************************************** - * A hook point to supply scope for members. - * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this. - */ -Scope *AttribDeclaration::newScope(Scope *sc) -{ - return sc; -} - -void AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds) -{ - Dsymbols *d = include(sc); - - if (d) - { - Scope *sc2 = newScope(sc); - - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - //printf("\taddMember %s to %s\n", s->toChars(), sds->toChars()); - s->addMember(sc2, sds); - } - - if (sc2 != sc) - sc2->pop(); - } -} - -void AttribDeclaration::setScope(Scope *sc) -{ - Dsymbols *d = include(sc); - - //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - Scope *sc2 = newScope(sc); - - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->setScope(sc2); - } - - if (sc2 != sc) - sc2->pop(); - } -} - -void AttribDeclaration::importAll(Scope *sc) -{ - Dsymbols *d = include(sc); - - //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); - if (d) - { - Scope *sc2 = newScope(sc); - - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->importAll(sc2); - } - - if (sc2 != sc) - sc2->pop(); - } -} - -void AttribDeclaration::addComment(const utf8_t *comment) -{ - //printf("AttribDeclaration::addComment %s\n", comment); - if (comment) - { - Dsymbols *d = include(NULL); - - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - //printf("AttribDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - } -} - -void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - Dsymbols *d = include(NULL); - - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -bool AttribDeclaration::hasPointers() -{ - Dsymbols *d = include(NULL); - - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - if (s->hasPointers()) - return true; - } - } - return false; -} - -bool AttribDeclaration::hasStaticCtorOrDtor() -{ - Dsymbols *d = include(NULL); - - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - if (s->hasStaticCtorOrDtor()) - return true; - } - } - return false; -} - -const char *AttribDeclaration::kind() const -{ - return "attribute"; -} - -bool AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - Dsymbols *d = include(NULL); - - return Dsymbol::oneMembers(d, ps, ident); -} - -void AttribDeclaration::checkCtorConstInit() -{ - Dsymbols *d = include(NULL); - - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - Dsymbols *d = include(NULL); - - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->addLocalClass(aclasses); - } - } -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); -} - -bool StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - bool t = Dsymbol::oneMembers(decl, ps, ident); - if (t && *ps) - { - /* This is to deal with the following case: - * struct Tick { - * template to(T) { const T to() { ... } } - * } - * For eponymous function templates, the 'const' needs to get attached to 'to' - * before the semantic analysis of 'to', so that template overloading based on the - * 'this' pointer can be successful. - */ - - FuncDeclaration *fd = (*ps)->isFuncDeclaration(); - if (fd) - { - /* Use storage_class2 instead of storage_class otherwise when we do .di generation - * we'll wind up with 'const const' rather than 'const'. - */ - /* Don't think we need to worry about mutually exclusive storage classes here - */ - fd->storage_class2 |= stc; - } - } - return t; -} - -void StorageClassDeclaration::addMember(Scope *sc, ScopeDsymbol *sds) -{ - Dsymbols *d = include(sc); - if (d) - { - Scope *sc2 = newScope(sc); - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - //printf("\taddMember %s to %s\n", s->toChars(), sds->toChars()); - // STClocal needs to be attached before the member is added to the scope (because it influences the parent symbol) - if (Declaration *decl = s->isDeclaration()) - { - decl->storage_class |= stc & STClocal; - if (StorageClassDeclaration *sdecl = s->isStorageClassDeclaration()) - { - sdecl->stc |= stc & STClocal; - } - } - s->addMember(sc2, sds); - } - if (sc2 != sc) - sc2->pop(); - } -} - -Scope *StorageClassDeclaration::newScope(Scope *sc) -{ - StorageClass scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - if (stc & (STCsafe | STCtrusted | STCsystem)) - scstc &= ~(STCsafe | STCtrusted | STCsystem); - scstc |= stc; - //printf("scstc = x%llx\n", scstc); - - return createNewScope(sc, scstc, sc->linkage, sc->cppmangle, - sc->protection, sc->explicitProtection, sc->aligndecl, - sc->inlining); -} - -/********************************* DeprecatedDeclaration ****************************/ - -DeprecatedDeclaration::DeprecatedDeclaration(Expression *msg, Dsymbols *decl) - : StorageClassDeclaration(STCdeprecated, decl) -{ - this->msg = msg; - this->msgstr = NULL; -} - -Dsymbol *DeprecatedDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new DeprecatedDeclaration(msg->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl)); -} - -/** - * Provides a new scope with `STCdeprecated` and `Scope.depdecl` set - * - * Calls `StorageClassDeclaration.newScope` (as it must be called or copied - * in any function overriding `newScope`), then set the `Scope`'s depdecl. - * - * Returns: - * Always a new scope, to use for this `DeprecatedDeclaration`'s members. - */ -Scope *DeprecatedDeclaration::newScope(Scope *sc) -{ - Scope *scx = StorageClassDeclaration::newScope(sc); - // The enclosing scope is deprecated as well - if (scx == sc) - scx = sc->push(); - scx->depdecl = this; - return scx; -} - -void DeprecatedDeclaration::setScope(Scope *sc) -{ - //printf("DeprecatedDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol::setScope(sc); // for forward reference - return AttribDeclaration::setScope(sc); -} - -const char *DeprecatedDeclaration::getMessage() -{ - if (Scope *sc = _scope) - { - _scope = NULL; - - sc = sc->startCTFE(); - msg = expressionSemantic(msg, sc); - msg = resolveProperties(sc, msg); - sc = sc->endCTFE(); - msg = msg->ctfeInterpret(); - - if (StringExp *se = msg->toStringExp()) - msgstr = (char *)se->string; - else - msg->error("compile time constant expected, not `%s`", msg->toChars()); - } - return msgstr; -} - -/********************************* LinkDeclaration ****************************/ - -LinkDeclaration::LinkDeclaration(LINK p, Dsymbols *decl) - : AttribDeclaration(decl) -{ - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = (p == LINKsystem) ? target.systemLinkage() : p; -} - -LinkDeclaration *LinkDeclaration::create(LINK p, Dsymbols *decl) -{ - return new LinkDeclaration(p, decl); -} - -Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); -} - -Scope *LinkDeclaration::newScope(Scope *sc) -{ - return createNewScope(sc, sc->stc, this->linkage, sc->cppmangle, - sc->protection, sc->explicitProtection, sc->aligndecl, - sc->inlining); -} - -const char *LinkDeclaration::toChars() -{ - return "extern ()"; -} - -/********************************* CPPMangleDeclaration ****************************/ - -CPPMangleDeclaration::CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl) - : AttribDeclaration(decl) -{ - //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", p, decl); - cppmangle = p; -} - -Dsymbol *CPPMangleDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new CPPMangleDeclaration(cppmangle, Dsymbol::arraySyntaxCopy(decl)); -} - -Scope *CPPMangleDeclaration::newScope(Scope *sc) -{ - return createNewScope(sc, sc->stc, LINKcpp, this->cppmangle, - sc->protection, sc->explicitProtection, sc->aligndecl, - sc->inlining); -} - -const char *CPPMangleDeclaration::toChars() -{ - return "extern ()"; -} - -/********************************* ProtDeclaration ****************************/ - -/** - * Params: - * loc = source location of attribute token - * p = protection attribute data - * decl = declarations which are affected by this protection attribute - */ -ProtDeclaration::ProtDeclaration(Loc loc, Prot p, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->protection = p; - this->pkg_identifiers = NULL; - //printf("decl = %p\n", decl); -} - -/** - * Params: - * loc = source location of attribute token - * pkg_identifiers = list of identifiers for a qualified package name - * decl = declarations which are affected by this protection attribute - */ -ProtDeclaration::ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->protection.kind = Prot::package_; - this->protection.pkg = NULL; - this->pkg_identifiers = pkg_identifiers; -} - -Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - if (protection.kind == Prot::package_) - return new ProtDeclaration(this->loc, pkg_identifiers, Dsymbol::arraySyntaxCopy(decl)); - else - return new ProtDeclaration(this->loc, protection, Dsymbol::arraySyntaxCopy(decl)); -} - -Scope *ProtDeclaration::newScope(Scope *sc) -{ - if (pkg_identifiers) - dsymbolSemantic(this, sc); - return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle, - this->protection, 1, sc->aligndecl, - sc->inlining); -} - -void ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds) -{ - if (pkg_identifiers) - { - Dsymbol* tmp; - Package::resolve(pkg_identifiers, &tmp, NULL); - protection.pkg = tmp ? tmp->isPackage() : NULL; - pkg_identifiers = NULL; - } - - if (protection.kind == Prot::package_ && protection.pkg && sc->_module) - { - Module *m = sc->_module; - - // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if - // each package's .isModule() properites are equal. - // - // Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null. - // This breaks package declarations of the package in question if they are declared in - // the same package.d file, which _do_ have a module associated with them, and hence a non-null - // isModule() - if (!m->isPackage() || !protection.pkg->ident->equals(m->isPackage()->ident)) - { - Package* pkg = m->parent ? m->parent->isPackage() : NULL; - if (!pkg || !protection.pkg->isAncestorPackageOf(pkg)) - error("does not bind to one of ancestor packages of module `%s`", - m->toPrettyChars(true)); - } - } - - return AttribDeclaration::addMember(sc, sds); -} - -const char *ProtDeclaration::kind() const -{ - return "protection attribute"; -} - -const char *ProtDeclaration::toPrettyChars(bool) -{ - assert(protection.kind > Prot::undefined); - - OutBuffer buf; - buf.writeByte('\''); - protectionToBuffer(&buf, protection); - buf.writeByte('\''); - return buf.extractChars(); -} - -/********************************* AlignDeclaration ****************************/ - -AlignDeclaration::AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ealign = ealign; - this->salign = 0; -} - -Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new AlignDeclaration(loc, - ealign ? ealign->syntaxCopy() : NULL, - Dsymbol::arraySyntaxCopy(decl)); -} - -Scope *AlignDeclaration::newScope(Scope *sc) -{ - return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle, - sc->protection, sc->explicitProtection, this, - sc->inlining); -} - -structalign_t AlignDeclaration::getAlignment(Scope *sc) -{ - if (salign != 0) - return salign; - - if (!ealign) - return salign = STRUCTALIGN_DEFAULT; - - sc = sc->startCTFE(); - ealign = expressionSemantic(ealign, sc); - ealign = resolveProperties(sc, ealign); - sc = sc->endCTFE(); - ealign = ealign->ctfeInterpret(); - - if (ealign->op == TOKerror) - return salign = STRUCTALIGN_DEFAULT; - - Type *tb = ealign->type->toBasetype(); - sinteger_t n = ealign->toInteger(); - - if (n < 1 || n & (n - 1) || STRUCTALIGN_DEFAULT < n || !tb->isintegral()) - { - ::error(loc, "alignment must be an integer positive power of 2, not %s", ealign->toChars()); - return salign = STRUCTALIGN_DEFAULT; - } - - return salign = (structalign_t)n; -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->isunion = isunion; - this->sem = 0; - this->anonoffset = 0; - this->anonstructsize = 0; - this->anonalignsize = 0; -} - -Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); -} - -void AnonDeclaration::setScope(Scope *sc) -{ - //printf("AnonDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol::setScope(sc); - AttribDeclaration::setScope(sc); -} - -void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); - - if (decl) - { - /* This works by treating an AnonDeclaration as an aggregate 'member', - * so in order to place that member we need to compute the member's - * size and alignment. - */ - - size_t fieldstart = ad->fields.length; - - /* Hackishly hijack ad's structsize and alignsize fields - * for use in our fake anon aggregate member. - */ - unsigned savestructsize = ad->structsize; - unsigned savealignsize = ad->alignsize; - ad->structsize = 0; - ad->alignsize = 0; - - unsigned offset = 0; - for (size_t i = 0; i < decl->length; i++) - { - Dsymbol *s = (*decl)[i]; - s->setFieldOffset(ad, &offset, this->isunion); - if (this->isunion) - offset = 0; - } - - /* Bugzilla 13613: If the fields in this->members had been already - * added in ad->fields, just update *poffset for the subsequent - * field offset calculation. - */ - if (fieldstart == ad->fields.length) - { - ad->structsize = savestructsize; - ad->alignsize = savealignsize; - *poffset = ad->structsize; - return; - } - - anonstructsize = ad->structsize; - anonalignsize = ad->alignsize; - ad->structsize = savestructsize; - ad->alignsize = savealignsize; - - // 0 sized structs are set to 1 byte - // TODO: is this corect hebavior? - if (anonstructsize == 0) - { - anonstructsize = 1; - anonalignsize = 1; - } - - assert(_scope); - structalign_t alignment = _scope->alignment(); - - /* Given the anon 'member's size and alignment, - * go ahead and place it. - */ - anonoffset = AggregateDeclaration::placeField( - poffset, - anonstructsize, anonalignsize, alignment, - &ad->structsize, &ad->alignsize, - isunion); - - // Add to the anon fields the base offset of this anonymous aggregate - //printf("anon fields, anonoffset = %d\n", anonoffset); - for (size_t i = fieldstart; i < ad->fields.length; i++) - { - VarDeclaration *v = ad->fields[i]; - //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset); - v->offset += anonoffset; - } - } -} - -const char *AnonDeclaration::kind() const -{ - return (isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); - assert(!s); - return new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), - Dsymbol::arraySyntaxCopy(decl)); -} - -Scope *PragmaDeclaration::newScope(Scope *sc) -{ - if (ident == Id::Pinline) - { - PINLINE inlining = PINLINEdefault; - if (!args || args->length == 0) - inlining = PINLINEdefault; - else if (args->length != 1) - { - error("one boolean expression expected for pragma(inline), not %d", args->length); - args->setDim(1); - (*args)[0] = new ErrorExp(); - } - else - { - Expression *e = (*args)[0]; - - if (e->op != TOKint64 || !e->type->equals(Type::tbool)) - { - if (e->op != TOKerror) - { - error("pragma(inline, true or false) expected, not %s", e->toChars()); - (*args)[0] = new ErrorExp(); - } - } - else if (e->isBool(true)) - inlining = PINLINEalways; - else if (e->isBool(false)) - inlining = PINLINEnever; - } - - return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle, - sc->protection, sc->explicitProtection, sc->aligndecl, - inlining); - } - if (ident == Id::printf || ident == Id::scanf) - { - Scope *sc2 = sc->push(); - - if (ident == Id::printf) - // Override previous setting, never let both be set - sc2->flags = (sc2->flags & ~SCOPEscanf) | SCOPEprintf; - else - sc2->flags = (sc2->flags & ~SCOPEprintf) | SCOPEscanf; - - return sc2; - } - return sc; -} - -const char *PragmaDeclaration::kind() const -{ - return "pragma"; -} - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); -} - -bool ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Dsymbols *d = condition->include(NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps, ident); - } - else - { - bool res = (Dsymbol::oneMembers( decl, ps, ident) && *ps == NULL && - Dsymbol::oneMembers(elsedecl, ps, ident) && *ps == NULL); - *ps = NULL; - return res; - } -} - -// Decide if 'then' or 'else' code should be included - -Dsymbols *ConditionalDeclaration::include(Scope *sc) -{ - //printf("ConditionalDeclaration::include(sc = %p) _scope = %p\n", sc, _scope); - - if (errors) - return NULL; - - assert(condition); - return condition->include(_scope ? _scope : sc) ? decl : elsedecl; -} - -void ConditionalDeclaration::setScope(Scope *sc) -{ - Dsymbols *d = include(sc); - - //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->setScope(sc); - } - } -} - -void ConditionalDeclaration::addComment(const utf8_t *comment) -{ - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - - if (comment) - { - Dsymbols *d = decl; - - for (int j = 0; j < 2; j++) - { - if (d) - { - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - d = elsedecl; - } - } -} - -/***************************** StaticIfDeclaration ****************************/ - -StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Dsymbols *decl, Dsymbols *elsedecl) - : ConditionalDeclaration(condition, decl, elsedecl) -{ - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - scopesym = NULL; - addisdone = false; - onStack = false; -} - -Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new StaticIfDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); -} - -/**************************************** - * Different from other AttribDeclaration subclasses, include() call requires - * the completion of addMember and setScope phases. - */ -Dsymbols *StaticIfDeclaration::include(Scope *sc) -{ - //printf("StaticIfDeclaration::include(sc = %p) _scope = %p\n", sc, _scope); - - if (errors || onStack) - return NULL; - onStack = true; - Dsymbols *d; - - if (condition->inc == 0) - { - assert(scopesym); // addMember is already done - assert(_scope); // setScope is already done - - d = ConditionalDeclaration::include(_scope); - - if (d && !addisdone) - { - // Add members lazily. - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->addMember(_scope, scopesym); - } - - // Set the member scopes lazily. - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->setScope(_scope); - } - - addisdone = true; - } - onStack = false; - return d; - } - else - { - d = ConditionalDeclaration::include(sc); - onStack = false; - return d; - } -} - -void StaticIfDeclaration::addMember(Scope *, ScopeDsymbol *sds) -{ - //printf("StaticIfDeclaration::addMember() '%s'\n", toChars()); - /* This is deferred until the condition evaluated later (by the include() call), - * so that expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this->scopesym = sds; -} - -void StaticIfDeclaration::importAll(Scope *) -{ - // do not evaluate condition before semantic pass -} - -void StaticIfDeclaration::setScope(Scope *sc) -{ - // do not evaluate condition before semantic pass - - // But do set the scope, in case we need it for forward referencing - Dsymbol::setScope(sc); -} - -const char *StaticIfDeclaration::kind() const -{ - return "static if"; -} - -/***************************** StaticForeachDeclaration ***********************/ - -/* Static foreach at declaration scope, like: - * static foreach (i; [0, 1, 2]){ } - */ - -StaticForeachDeclaration::StaticForeachDeclaration(StaticForeach *sfe, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->sfe = sfe; - this->scopesym = NULL; - this->onStack = false; - this->cached = false; - this->cache = NULL; -} - -Dsymbol *StaticForeachDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - return new StaticForeachDeclaration( - sfe->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl)); -} - -bool StaticForeachDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - // Required to support IFTI on a template that contains a - // `static foreach` declaration. `super.oneMember` calls - // include with a `null` scope. As `static foreach` requires - // the scope for expansion, `oneMember` can only return a - // precise result once `static foreach` has been expanded. - if (cached) - { - return AttribDeclaration::oneMember(ps, ident); - } - *ps = NULL; // a `static foreach` declaration may in general expand to multiple symbols - return false; -} - -Dsymbols *StaticForeachDeclaration::include(Scope *) -{ - if (errors || onStack) - return NULL; - if (cached) - { - assert(!onStack); - return cache; - } - onStack = true; - - if (_scope) - { - staticForeachPrepare(sfe, _scope); // lower static foreach aggregate - } - if (!staticForeachReady(sfe)) - { - onStack = false; - return NULL; // TODO: ok? - } - - // expand static foreach - Dsymbols *d = makeTupleForeachStaticDecl(_scope, sfe->aggrfe, decl, sfe->needExpansion); - if (d) // process generated declarations - { - // Add members lazily. - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->addMember(_scope, scopesym); - } - // Set the member scopes lazily. - for (size_t i = 0; i < d->length; i++) - { - Dsymbol *s = (*d)[i]; - s->setScope(_scope); - } - } - onStack = false; - cached = true; - cache = d; - return d; -} - -void StaticForeachDeclaration::addMember(Scope *, ScopeDsymbol *sds) -{ - // used only for caching the enclosing symbol - this->scopesym = sds; -} - -void StaticForeachDeclaration::addComment(const utf8_t *) -{ - // do nothing - // change this to give semantics to documentation comments on static foreach declarations -} - -void StaticForeachDeclaration::setScope(Scope *sc) -{ - // do not evaluate condition before semantic pass - // But do set the scope, in case we need it for forward referencing - Dsymbol::setScope(sc); -} - -void StaticForeachDeclaration::importAll(Scope *) -{ - // do not evaluate aggregate before semantic pass -} - -const char *StaticForeachDeclaration::kind() const -{ - return "static foreach"; -} - -/*********************************************************** - * Collection of declarations that stores foreach index variables in a - * local symbol table. Other symbols declared within are forwarded to - * another scope, like: - * - * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict. - * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STClocal - * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable - * } - * - * static foreach (i; 0.. 10) - * { - * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope - * } - * - * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop - * - * A StaticForeachDeclaration generates one - * ForwardingAttribDeclaration for each expansion of its body. The - * AST of the ForwardingAttribDeclaration contains both the `static - * foreach` variables and the respective copy of the `static foreach` - * body. The functionality is achieved by using a - * ForwardingScopeDsymbol as the parent symbol for the generated - * declarations. - */ - -ForwardingAttribDeclaration::ForwardingAttribDeclaration(Dsymbols *decl) - : AttribDeclaration(decl) -{ - sym = new ForwardingScopeDsymbol(NULL); - sym->symtab = new DsymbolTable(); -} - -/************************************** - * Use the ForwardingScopeDsymbol as the parent symbol for members. - */ -Scope *ForwardingAttribDeclaration::newScope(Scope *sc) -{ - return sc->push(sym); -} - -/*************************************** - * Lazily initializes the scope to forward to. - */ -void ForwardingAttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds) -{ - parent = sym->parent = sym->forward = sds; - return AttribDeclaration::addMember(sc, sym); -} - -/***************************** CompileDeclaration *****************************/ - -// These are mixin declarations, like mixin("int x"); - -CompileDeclaration::CompileDeclaration(Loc loc, Expressions *exps) - : AttribDeclaration(NULL) -{ - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); - this->loc = loc; - this->exps = exps; - this->scopesym = NULL; - this->compiled = false; -} - -Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *) -{ - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - return new CompileDeclaration(loc, Expression::arraySyntaxCopy(exps)); -} - -void CompileDeclaration::addMember(Scope *, ScopeDsymbol *sds) -{ - //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); - this->scopesym = sds; -} - -void CompileDeclaration::setScope(Scope *sc) -{ - Dsymbol::setScope(sc); -} - -const char *CompileDeclaration::kind() const -{ - return "mixin"; -} - -/***************************** UserAttributeDeclaration *****************************/ - -UserAttributeDeclaration::UserAttributeDeclaration(Expressions *atts, Dsymbols *decl) - : AttribDeclaration(decl) -{ - //printf("UserAttributeDeclaration()\n"); - this->atts = atts; -} - -Dsymbol *UserAttributeDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars()); - assert(!s); - return new UserAttributeDeclaration( - Expression::arraySyntaxCopy(this->atts), - Dsymbol::arraySyntaxCopy(decl)); -} - -Scope *UserAttributeDeclaration::newScope(Scope *sc) -{ - Scope *sc2 = sc; - if (atts && atts->length) - { - // create new one for changes - sc2 = sc->copy(); - sc2->userAttribDecl = this; - } - return sc2; -} - -void UserAttributeDeclaration::setScope(Scope *sc) -{ - //printf("UserAttributeDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol::setScope(sc); // for forward reference of UDAs - - return AttribDeclaration::setScope(sc); -} - -void udaExpressionEval(Scope *sc, Expressions *exps) -{ - for (size_t i = 0; i < exps->length; i++) - { - Expression *e = (*exps)[i]; - if (e) - { - e = expressionSemantic(e, sc); - if (definitelyValueParameter(e)) - e = e->ctfeInterpret(); - if (e->op == TOKtuple) - { - TupleExp *te = (TupleExp *)e; - udaExpressionEval(sc, te->exps); - } - (*exps)[i] = e; - } - } -} - -Expressions *UserAttributeDeclaration::concat(Expressions *udas1, Expressions *udas2) -{ - Expressions *udas; - if (!udas1 || udas1->length == 0) - udas = udas2; - else if (!udas2 || udas2->length == 0) - udas = udas1; - else - { - /* Create a new tuple that combines them - * (do not append to left operand, as this is a copy-on-write operation) - */ - udas = new Expressions(); - udas->push(new TupleExp(Loc(), udas1)); - udas->push(new TupleExp(Loc(), udas2)); - } - return udas; -} - -Expressions *UserAttributeDeclaration::getAttributes() -{ - if (Scope *sc = _scope) - { - _scope = NULL; - arrayExpressionSemantic(atts, sc); - } - - Expressions *exps = new Expressions(); - if (userAttribDecl) - exps->push(new TupleExp(Loc(), userAttribDecl->getAttributes())); - if (atts && atts->length) - exps->push(new TupleExp(Loc(), atts)); - - return exps; -} - -const char *UserAttributeDeclaration::kind() const -{ - return "UserAttribute"; -} |