aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/func.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/func.c')
-rw-r--r--gcc/d/dmd/func.c3161
1 files changed, 0 insertions, 3161 deletions
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
deleted file mode 100644
index b8e1e31..0000000
--- a/gcc/d/dmd/func.c
+++ /dev/null
@@ -1,3161 +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/func.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "init.h"
-#include "declaration.h"
-#include "attrib.h"
-#include "expression.h"
-#include "scope.h"
-#include "mtype.h"
-#include "aggregate.h"
-#include "identifier.h"
-#include "id.h"
-#include "module.h"
-#include "statement.h"
-#include "statement_rewrite_walker.h"
-#include "template.h"
-#include "hdrgen.h"
-#include "target.h"
-#include "parse.h"
-#include "root/rmem.h"
-#include "visitor.h"
-
-bool checkNestedRef(Dsymbol *s, Dsymbol *p);
-int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
-TypeIdentifier *getThrowable();
-
-bool MODimplicitConv(MOD modfrom, MOD modto);
-MATCH MODmethodConv(MOD modfrom, MOD modto);
-
-/***********************************************************
- * Tuple of result identifier (possibly null) and statement.
- * This is used to store out contracts: out(id){ ensure }
- */
-Ensure::Ensure()
-{
- this->id = NULL;
- this->ensure = NULL;
-}
-
-Ensure::Ensure(Identifier *id, Statement *ensure)
-{
- this->id = id;
- this->ensure = ensure;
-}
-
-Ensure Ensure::syntaxCopy()
-{
- return Ensure(id, ensure->syntaxCopy());
-}
-
-/*****************************************
- * Do syntax copy of an array of Ensure's.
- */
-Ensures *Ensure::arraySyntaxCopy(Ensures *a)
-{
- Ensures *b = NULL;
- if (a)
- {
- b = a->copy();
- for (size_t i = 0; i < a->length; i++)
- (*b)[i] = (*a)[i].syntaxCopy();
- }
- return b;
-}
-
-/********************************* FuncDeclaration ****************************/
-
-FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
- : Declaration(id)
-{
- //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
- //printf("storage_class = x%x\n", storage_class);
- this->storage_class = storage_class;
- this->type = type;
- if (type)
- {
- // Normalize storage_class, because function-type related attributes
- // are already set in the 'type' in parsing phase.
- this->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
- }
- this->loc = loc;
- this->endloc = endloc;
- fthrows = NULL;
- frequire = NULL;
- fdrequire = NULL;
- fdensure = NULL;
- mangleString = NULL;
- vresult = NULL;
- returnLabel = NULL;
- fensure = NULL;
- frequires = NULL;
- fensures = NULL;
- fbody = NULL;
- localsymtab = NULL;
- vthis = NULL;
- v_arguments = NULL;
- v_argptr = NULL;
- parameters = NULL;
- labtab = NULL;
- overnext = NULL;
- overnext0 = NULL;
- vtblIndex = -1;
- hasReturnExp = 0;
- naked = false;
- generated = false;
- inlineStatusExp = ILSuninitialized;
- inlineStatusStmt = ILSuninitialized;
- inlining = PINLINEdefault;
- inlineNest = 0;
- ctfeCode = NULL;
- isArrayOp = 0;
- semantic3Errors = false;
- fes = NULL;
- interfaceVirtual = NULL;
- introducing = 0;
- tintro = NULL;
- /* The type given for "infer the return type" is a TypeFunction with
- * NULL for the return type.
- */
- inferRetType = (type && type->nextOf() == NULL);
- storage_class2 = 0;
- hasReturnExp = 0;
- nrvo_can = 1;
- nrvo_var = NULL;
- shidden = NULL;
- builtin = BUILTINunknown;
- tookAddressOf = 0;
- requiresClosure = false;
- inlinedNestedCallees = NULL;
- flags = 0;
- returns = NULL;
- gotos = NULL;
- selector = NULL;
-}
-
-FuncDeclaration *FuncDeclaration::create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
-{
- return new FuncDeclaration(loc, endloc, id, storage_class, type);
-}
-
-Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
- FuncDeclaration *f =
- s ? (FuncDeclaration *)s
- : new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy());
- f->frequires = frequires ? Statement::arraySyntaxCopy(frequires) : NULL;
- f->fensures = fensures ? Ensure::arraySyntaxCopy(fensures) : NULL;
- f->fbody = fbody ? fbody->syntaxCopy() : NULL;
- assert(!fthrows); // deprecated
- return f;
-}
-
-// Returns true if a contract can appear without a function body.
-bool allowsContractWithoutBody(FuncDeclaration *funcdecl)
-{
- assert(!funcdecl->fbody);
-
- /* Contracts can only appear without a body when they are virtual
- * interface functions or abstract.
- */
- Dsymbol *parent = funcdecl->toParent();
- InterfaceDeclaration *id = parent->isInterfaceDeclaration();
-
- if (!funcdecl->isAbstract() &&
- (funcdecl->fensures || funcdecl->frequires) &&
- !(id && funcdecl->isVirtual()))
- {
- ClassDeclaration *cd = parent->isClassDeclaration();
- if (!(cd && cd->isAbstract()))
- return false;
- }
- return true;
-}
-
-/****************************************************
- * Determine whether an 'out' contract is declared inside
- * the given function or any of its overrides.
- * Params:
- * fd = the function to search
- * Returns:
- * true found an 'out' contract
- * false didn't find one
- */
-bool FuncDeclaration::needsFensure(FuncDeclaration *fd)
-{
- if (fd->fensures)
- return true;
-
- for (size_t i = 0; i < fd->foverrides.length; i++)
- {
- FuncDeclaration *fdv = fd->foverrides[i];
-
- if (fdv->fensure)
- return true;
-
- if (needsFensure(fdv))
- return true;
- }
- return false;
-}
-
-/****************************************************
- * Check whether result variable can be built.
- * Returns:
- * `true` if the function has a return type that
- * is different from `void`.
- */
-static bool canBuildResultVar(FuncDeclaration *fd)
-{
- TypeFunction *f = (TypeFunction *)fd->type;
- return f && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid;
-}
-
-/****************************************************
- * Rewrite contracts as statements.
- */
-void FuncDeclaration::buildEnsureRequire()
-{
- if (frequires)
- {
- /* in { statements1... }
- * in { statements2... }
- * ...
- * becomes:
- * in { { statements1... } { statements2... } ... }
- */
- assert(frequires->length);
- Loc loc = (*frequires)[0]->loc;
- Statements *s = new Statements;
- for (size_t i = 0; i < frequires->length; i++)
- {
- Statement *r = (*frequires)[i];
- s->push(new ScopeStatement(r->loc, r, r->loc));
- }
- frequire = new CompoundStatement(loc, s);
- }
-
- if (fensures)
- {
- /* out(id1) { statements1... }
- * out(id2) { statements2... }
- * ...
- * becomes:
- * out(__result) { { ref id1 = __result; { statements1... } }
- * { ref id2 = __result; { statements2... } } ... }
- */
- assert(fensures->length);
- Loc loc = (*fensures)[0].ensure->loc;
- Statements *s = new Statements;
- for (size_t i = 0; i < fensures->length; i++)
- {
- Ensure r = (*fensures)[i];
- if (r.id && canBuildResultVar(this))
- {
- Loc rloc = r.ensure->loc;
- IdentifierExp *resultId = new IdentifierExp(rloc, Id::result);
- ExpInitializer *init = new ExpInitializer(rloc, resultId);
- StorageClass stc = STCref | STCtemp | STCresult;
- VarDeclaration *decl = new VarDeclaration(rloc, NULL, r.id, init);
- decl->storage_class = stc;
- ExpStatement *sdecl = new ExpStatement(rloc, decl);
- s->push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
- }
- else
- {
- s->push(r.ensure);
- }
- }
- fensure = new CompoundStatement(loc, s);
- }
-
- if (!isVirtual())
- return;
-
- /* Rewrite contracts as nested functions, then call them. Doing it as nested
- * functions means that overriding functions can call them.
- */
- TypeFunction *f = (TypeFunction *)type;
-
- if (frequire)
- {
- /* in { ... }
- * becomes:
- * void __require() { ... }
- * __require();
- */
- Loc loc = frequire->loc;
- TypeFunction *tf = new TypeFunction(ParameterList(), Type::tvoid, LINKd);
- tf->isnothrow = f->isnothrow;
- tf->isnogc = f->isnogc;
- tf->purity = f->purity;
- tf->trust = f->trust;
- FuncDeclaration *fd = new FuncDeclaration(loc, loc,
- Id::require, STCundefined, tf);
- fd->fbody = frequire;
- Statement *s1 = new ExpStatement(loc, fd);
- Expression *e = new CallExp(loc, new VarExp(loc, fd, false), (Expressions *)NULL);
- Statement *s2 = new ExpStatement(loc, e);
- frequire = new CompoundStatement(loc, s1, s2);
- fdrequire = fd;
- }
-
- if (fensure)
- {
- /* out (result) { ... }
- * becomes:
- * void __ensure(ref tret result) { ... }
- * __ensure(result);
- */
- Loc loc = fensure->loc;
- Parameters *fparams = new Parameters();
- Parameter *p = NULL;
- if (canBuildResultVar(this))
- {
- p = new Parameter(STCref | STCconst, f->nextOf(), Id::result, NULL, NULL);
- fparams->push(p);
- }
- TypeFunction *tf = new TypeFunction(ParameterList(fparams), Type::tvoid, LINKd);
- tf->isnothrow = f->isnothrow;
- tf->isnogc = f->isnogc;
- tf->purity = f->purity;
- tf->trust = f->trust;
- FuncDeclaration *fd = new FuncDeclaration(loc, loc,
- Id::ensure, STCundefined, tf);
- fd->fbody = fensure;
- Statement *s1 = new ExpStatement(loc, fd);
- Expression *eresult = NULL;
- if (canBuildResultVar(this))
- eresult = new IdentifierExp(loc, Id::result);
- Expression *e = new CallExp(loc, new VarExp(loc, fd, false), eresult);
- Statement *s2 = new ExpStatement(loc, e);
- fensure = new CompoundStatement(loc, s1, s2);
- fdensure = fd;
- }
-}
-
-/****************************************************
- * Resolve forward reference of function signature -
- * parameter types, return type, and attributes.
- * Returns false if any errors exist in the signature.
- */
-bool FuncDeclaration::functionSemantic()
-{
- if (!_scope)
- return !errors;
-
- if (!originalType) // semantic not yet run
- {
- TemplateInstance *spec = isSpeculative();
- unsigned olderrs = global.errors;
- unsigned oldgag = global.gag;
- if (global.gag && !spec)
- global.gag = 0;
- dsymbolSemantic(this, _scope);
- global.gag = oldgag;
- if (spec && global.errors != olderrs)
- spec->errors = (global.errors - olderrs != 0);
- if (olderrs != global.errors) // if errors compiling this function
- return false;
- }
-
- // if inferring return type, sematic3 needs to be run
- // - When the function body contains any errors, we cannot assume
- // the inferred return type is valid.
- // So, the body errors should become the function signature error.
- if (inferRetType && type && !type->nextOf())
- return functionSemantic3();
-
- TemplateInstance *ti;
- if (isInstantiated() && !isVirtualMethod() &&
- ((ti = parent->isTemplateInstance()) == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == ident))
- {
- AggregateDeclaration *ad = isMember2();
- if (ad && ad->sizeok != SIZEOKdone)
- {
- /* Currently dmd cannot resolve forward references per methods,
- * then setting SIZOKfwd is too conservative and would break existing code.
- * So, just stop method attributes inference until ad->semantic() done.
- */
- //ad->sizeok = SIZEOKfwd;
- }
- else
- return functionSemantic3() || !errors;
- }
-
- if (storage_class & STCinference)
- return functionSemantic3() || !errors;
-
- return !errors;
-}
-
-/****************************************************
- * Resolve forward reference of function body.
- * Returns false if any errors exist in the body.
- */
-bool FuncDeclaration::functionSemantic3()
-{
- if (semanticRun < PASSsemantic3 && _scope)
- {
- /* Forward reference - we need to run semantic3 on this function.
- * If errors are gagged, and it's not part of a template instance,
- * we need to temporarily ungag errors.
- */
- TemplateInstance *spec = isSpeculative();
- unsigned olderrs = global.errors;
- unsigned oldgag = global.gag;
- if (global.gag && !spec)
- global.gag = 0;
- semantic3(this, _scope);
- global.gag = oldgag;
-
- // If it is a speculatively-instantiated template, and errors occur,
- // we need to mark the template as having errors.
- if (spec && global.errors != olderrs)
- spec->errors = (global.errors - olderrs != 0);
- if (olderrs != global.errors) // if errors compiling this function
- return false;
- }
-
- return !errors && !semantic3Errors;
-}
-
-/****************************************************
- * Check that this function type is properly resolved.
- * If not, report "forward reference error" and return true.
- */
-bool FuncDeclaration::checkForwardRef(Loc loc)
-{
- if (!functionSemantic())
- return true;
-
- /* No deco means the functionSemantic() call could not resolve
- * forward referenes in the type of this function.
- */
- if (!type->deco)
- {
- bool inSemantic3 = (inferRetType && semanticRun >= PASSsemantic3);
- ::error(loc, "forward reference to %s`%s`",
- (inSemantic3 ? "inferred return type of function " : ""),
- toChars());
- return true;
- }
- return false;
-}
-
-VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad)
-{
- if (ad)
- {
- VarDeclaration *v;
- {
- //printf("declareThis() %s\n", toChars());
- Type *thandle = ad->handleType();
- assert(thandle);
- thandle = thandle->addMod(type->mod);
- thandle = thandle->addStorageClass(storage_class);
- v = new ThisDeclaration(loc, thandle);
- v->storage_class |= STCparameter;
- if (thandle->ty == Tstruct)
- {
- v->storage_class |= STCref;
-
- // if member function is marked 'inout', then 'this' is 'return ref'
- if (type->ty == Tfunction && ((TypeFunction *)type)->iswild & 2)
- v->storage_class |= STCreturn;
- }
- if (type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)type;
- if (tf->isreturn)
- v->storage_class |= STCreturn;
- if (tf->isscope)
- v->storage_class |= STCscope;
- }
- if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
- v->storage_class |= STCmaybescope;
-
- dsymbolSemantic(v, sc);
- if (!sc->insert(v))
- assert(0);
- v->parent = this;
- return v;
- }
- }
- else if (isNested())
- {
- /* The 'this' for a nested function is the link to the
- * enclosing function's stack frame.
- * Note that nested functions and member functions are disjoint.
- */
- VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo());
- v->storage_class |= STCparameter;
- if (type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)type;
- if (tf->isreturn)
- v->storage_class |= STCreturn;
- if (tf->isscope)
- v->storage_class |= STCscope;
- }
- if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
- v->storage_class |= STCmaybescope;
-
- dsymbolSemantic(v, sc);
- if (!sc->insert(v))
- assert(0);
- v->parent = this;
- return v;
- }
-
- return NULL;
-}
-
-bool FuncDeclaration::equals(RootObject *o)
-{
- if (this == o)
- return true;
-
- Dsymbol *s = isDsymbol(o);
- if (s)
- {
- FuncDeclaration *fd1 = this;
- FuncDeclaration *fd2 = s->isFuncDeclaration();
- if (!fd2)
- return false;
-
- FuncAliasDeclaration *fa1 = fd1->isFuncAliasDeclaration();
- FuncAliasDeclaration *fa2 = fd2->isFuncAliasDeclaration();
- if (fa1 && fa2)
- {
- return fa1->toAliasFunc()->equals(fa2->toAliasFunc()) &&
- fa1->hasOverloads == fa2->hasOverloads;
- }
-
- if (fa1 && (fd1 = fa1->toAliasFunc())->isUnique() && !fa1->hasOverloads)
- fa1 = NULL;
- if (fa2 && (fd2 = fa2->toAliasFunc())->isUnique() && !fa2->hasOverloads)
- fa2 = NULL;
- if ((fa1 != NULL) != (fa2 != NULL))
- return false;
-
- return fd1->toParent()->equals(fd2->toParent()) &&
- fd1->ident->equals(fd2->ident) && fd1->type->equals(fd2->type);
- }
- return false;
-}
-
-/****************************************************
- * Declare result variable lazily.
- */
-
-void FuncDeclaration::buildResultVar(Scope *sc, Type *tret)
-{
- if (!vresult)
- {
- Loc loc = fensure ? fensure->loc : this->loc;
-
- /* If inferRetType is true, tret may not be a correct return type yet.
- * So, in here it may be a temporary type for vresult, and after
- * fbody->semantic() running, vresult->type might be modified.
- */
- vresult = new VarDeclaration(loc, tret, Id::result, NULL);
- vresult->storage_class |= STCnodtor | STCtemp;
- if (!isVirtual())
- vresult->storage_class |= STCconst;
- vresult->storage_class |= STCresult;
-
- // set before the semantic() for checkNestedReference()
- vresult->parent = this;
- }
-
- if (sc && vresult->semanticRun == PASSinit)
- {
- TypeFunction *tf = type->toTypeFunction();
- if (tf->isref)
- vresult->storage_class |= STCref;
- vresult->type = tret;
-
- dsymbolSemantic(vresult, sc);
-
- if (!sc->insert(vresult))
- error("out result %s is already defined", vresult->toChars());
- assert(vresult->parent == this);
- }
-}
-
-/****************************************************
- * Merge into this function the 'in' contracts of all it overrides.
- * 'in's are OR'd together, i.e. only one of them needs to pass.
- */
-
-Statement *FuncDeclaration::mergeFrequire(Statement *sf)
-{
- /* If a base function and its override both have an IN contract, then
- * only one of them needs to succeed. This is done by generating:
- *
- * void derived.in() {
- * try {
- * base.in();
- * }
- * catch () {
- * ... body of derived.in() ...
- * }
- * }
- *
- * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
- * If base.in() throws, then derived.in()'s body is executed.
- */
-
- /* Implementing this is done by having the overriding function call
- * nested functions (the fdrequire functions) nested inside the overridden
- * function. This requires that the stack layout of the calling function's
- * parameters and 'this' pointer be in the same place (as the nested
- * function refers to them).
- * This is easy for the parameters, as they are all on the stack in the same
- * place by definition, since it's an overriding function. The problem is
- * getting the 'this' pointer in the same place, since it is a local variable.
- * We did some hacks in the code generator to make this happen:
- * 1. always generate exception handler frame, or at least leave space for it
- * in the frame (Windows 32 SEH only)
- * 2. always generate an EBP style frame
- * 3. since 'this' is passed in a register that is subsequently copied into
- * a stack local, allocate that local immediately following the exception
- * handler block, so it is always at the same offset from EBP.
- */
- for (size_t i = 0; i < foverrides.length; i++)
- {
- FuncDeclaration *fdv = foverrides[i];
-
- /* The semantic pass on the contracts of the overridden functions must
- * be completed before code generation occurs.
- * https://issues.dlang.org/show_bug.cgi?id=3602
- */
- if (fdv->frequires && fdv->semanticRun != PASSsemantic3done)
- {
- assert(fdv->_scope);
- Scope *sc = fdv->_scope->push();
- sc->stc &= ~STCoverride;
- semantic3(fdv, sc);
- sc->pop();
- }
-
- sf = fdv->mergeFrequire(sf);
- if (sf && fdv->fdrequire)
- {
- //printf("fdv->frequire: %s\n", fdv->frequire->toChars());
- /* Make the call:
- * try { __require(); }
- * catch (Throwable) { frequire; }
- */
- Expression *eresult = NULL;
- Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, false), eresult);
- Statement *s2 = new ExpStatement(loc, e);
-
- Catch *c = new Catch(loc, getThrowable(), NULL, sf);
- c->internalCatch = true;
- Catches *catches = new Catches();
- catches->push(c);
- sf = new TryCatchStatement(loc, s2, catches);
- }
- else
- return NULL;
- }
- return sf;
-}
-
-/****************************************************
- * Merge into this function the 'out' contracts of all it overrides.
- * 'out's are AND'd together, i.e. all of them need to pass.
- */
-
-Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid)
-{
- /* Same comments as for mergeFrequire(), except that we take care
- * of generating a consistent reference to the 'result' local by
- * explicitly passing 'result' to the nested function as a reference
- * argument.
- * This won't work for the 'this' parameter as it would require changing
- * the semantic code for the nested function so that it looks on the parameter
- * list for the 'this' pointer, something that would need an unknown amount
- * of tweaking of various parts of the compiler that I'd rather leave alone.
- */
- for (size_t i = 0; i < foverrides.length; i++)
- {
- FuncDeclaration *fdv = foverrides[i];
-
- /* The semantic pass on the contracts of the overridden functions must
- * be completed before code generation occurs.
- * https://issues.dlang.org/show_bug.cgi?id=3602 and
- * https://issues.dlang.org/show_bug.cgi?id=5230
- */
- if (needsFensure(fdv) && fdv->semanticRun != PASSsemantic3done)
- {
- assert(fdv->_scope);
- Scope *sc = fdv->_scope->push();
- sc->stc &= ~STCoverride;
- semantic3(fdv, sc);
- sc->pop();
- }
-
- sf = fdv->mergeFensure(sf, oid);
- if (fdv->fdensure)
- {
- //printf("fdv->fensure: %s\n", fdv->fensure->toChars());
- // Make the call: __ensure(result)
- Expression *eresult = NULL;
- if (canBuildResultVar(this))
- {
- eresult = new IdentifierExp(loc, oid);
-
- Type *t1 = fdv->type->nextOf()->toBasetype();
- Type *t2 = this->type->nextOf()->toBasetype();
- if (t1->isBaseOf(t2, NULL))
- {
- /* Making temporary reference variable is necessary
- * in covariant return.
- * See bugzilla 5204 and 10479.
- */
- ExpInitializer *ei = new ExpInitializer(Loc(), eresult);
- VarDeclaration *v = new VarDeclaration(Loc(), t1, Identifier::generateId("__covres"), ei);
- v->storage_class |= STCtemp;
- DeclarationExp *de = new DeclarationExp(Loc(), v);
- VarExp *ve = new VarExp(Loc(), v);
- eresult = new CommaExp(Loc(), de, ve);
- }
- }
- Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, false), eresult);
- Statement *s2 = new ExpStatement(loc, e);
-
- if (sf)
- {
- sf = new CompoundStatement(sf->loc, s2, sf);
- }
- else
- sf = s2;
- }
- }
- return sf;
-}
-
-/****************************************************
- * Determine if 'this' overrides fd.
- * Return !=0 if it does.
- */
-
-int FuncDeclaration::overrides(FuncDeclaration *fd)
-{ int result = 0;
-
- if (fd->ident == ident)
- {
- int cov = type->covariant(fd->type);
- if (cov)
- { ClassDeclaration *cd1 = toParent()->isClassDeclaration();
- ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration();
-
- if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL))
- result = 1;
- }
- }
- return result;
-}
-
-/*************************************************
- * Find index of function in vtbl[0..length] that
- * this function overrides.
- * Prefer an exact match to a covariant one.
- * Params:
- * fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
- * Returns:
- * -1 didn't find one
- * -2 can't determine because of forward references
- */
-
-int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349)
-{
- //printf("findVtblIndex() %s\n", toChars());
- FuncDeclaration *mismatch = NULL;
- StorageClass mismatchstc = 0;
- int mismatchvi = -1;
- int exactvi = -1;
- int bestvi = -1;
- for (int vi = 0; vi < dim; vi++)
- {
- FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration();
- if (fdv && fdv->ident == ident)
- {
- if (type->equals(fdv->type)) // if exact match
- {
- if (fdv->parent->isClassDeclaration())
- {
- if (fdv->isFuture())
- {
- bestvi = vi;
- continue; // keep looking
- }
- return vi; // no need to look further
- }
-
- if (exactvi >= 0)
- {
- error("cannot determine overridden function");
- return exactvi;
- }
- exactvi = vi;
-
- bestvi = vi;
- continue;
- }
-
- StorageClass stc = 0;
- int cov = type->covariant(fdv->type, &stc, fix17349);
- //printf("\tbaseclass cov = %d\n", cov);
- switch (cov)
- {
- case 0: // types are distinct
- break;
-
- case 1:
- bestvi = vi; // covariant, but not identical
- break; // keep looking for an exact match
-
- case 2:
- mismatchvi = vi;
- mismatchstc = stc;
- mismatch = fdv; // overrides, but is not covariant
- break; // keep looking for an exact match
-
- case 3:
- return -2; // forward references
-
- default:
- assert(0);
- }
- }
- }
- if (bestvi == -1 && mismatch)
- {
- //type->print();
- //mismatch->type->print();
- //printf("%s %s\n", type->deco, mismatch->type->deco);
- //printf("stc = %llx\n", mismatchstc);
- if (mismatchstc)
- { // Fix it by modifying the type to add the storage classes
- type = type->addStorageClass(mismatchstc);
- bestvi = mismatchvi;
- }
- }
- return bestvi;
-}
-
-/*********************************
- * If function a function in a base class,
- * return that base class.
- * Params:
- * cd = class that function is in
- * Returns:
- * base class if overriding, NULL if not
- */
-BaseClass *FuncDeclaration::overrideInterface()
-{
- ClassDeclaration *cd = parent->isClassDeclaration();
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- int v = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.length);
- if (v >= 0)
- return b;
- }
- return NULL;
-}
-
-/****************************************************
- * Overload this FuncDeclaration with the new one f.
- * Return true if successful; i.e. no conflict.
- */
-
-bool FuncDeclaration::overloadInsert(Dsymbol *s)
-{
- //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars());
- assert(s != this);
-
- AliasDeclaration *ad = s->isAliasDeclaration();
- if (ad)
- {
- if (overnext)
- return overnext->overloadInsert(ad);
- if (!ad->aliassym && ad->type->ty != Tident && ad->type->ty != Tinstance)
- {
- //printf("\tad = '%s'\n", ad->type->toChars());
- return false;
- }
- overnext = ad;
- //printf("\ttrue: no conflict\n");
- return true;
- }
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td)
- {
- if (!td->funcroot)
- td->funcroot = this;
- if (overnext)
- return overnext->overloadInsert(td);
- overnext = td;
- return true;
- }
- FuncDeclaration *fd = s->isFuncDeclaration();
- if (!fd)
- return false;
-
- if (overnext)
- {
- td = overnext->isTemplateDeclaration();
- if (td)
- fd->overloadInsert(td);
- else
- return overnext->overloadInsert(fd);
- }
- overnext = fd;
- //printf("\ttrue: no conflict\n");
- return true;
-}
-
-/***************************************************
- * Visit each overloaded function/template in turn, and call
- * (*fp)(param, s) on it.
- * Exit when no more, or (*fp)(param, f) returns nonzero.
- * Returns:
- * ==0 continue
- * !=0 done
- */
-
-int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *))
-{
- Dsymbol *d;
- Dsymbol *next;
- for (d = fstart; d; d = next)
- {
- if (OverDeclaration *od = d->isOverDeclaration())
- {
- if (od->hasOverloads)
- {
- if (int r = overloadApply(od->aliassym, param, fp))
- return r;
- }
- else
- {
- if (int r = (*fp)(param, od->aliassym))
- return r;
- }
- next = od->overnext;
- }
- else if (FuncAliasDeclaration *fa = d->isFuncAliasDeclaration())
- {
- if (fa->hasOverloads)
- {
- if (int r = overloadApply(fa->funcalias, param, fp))
- return r;
- }
- else
- {
- FuncDeclaration *fd = fa->toAliasFunc();
- if (!fd)
- {
- d->error("is aliased to a function");
- break;
- }
- if (int r = (*fp)(param, fd))
- return r;
- }
- next = fa->overnext;
- }
- else if (AliasDeclaration *ad = d->isAliasDeclaration())
- {
- next = ad->toAlias();
- if (next == ad)
- break;
- if (next == fstart)
- break;
- }
- else if (TemplateDeclaration *td = d->isTemplateDeclaration())
- {
- if (int r = (*fp)(param, td))
- return r;
- next = td->overnext;
- }
- else
- {
- FuncDeclaration *fd = d->isFuncDeclaration();
- if (!fd)
- {
- d->error("is aliased to a function");
- break; // BUG: should print error message?
- }
- if (int r = (*fp)(param, fd))
- return r;
- next = fd->overnext;
- }
- }
- return 0;
-}
-
-/********************************************
- * If there are no overloads of function f, return that function,
- * otherwise return NULL.
- */
-
-FuncDeclaration *FuncDeclaration::isUnique()
-{
- struct ParamUnique
- {
- static int fp(void *param, Dsymbol *s)
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (!f)
- return 0;
- FuncDeclaration **pf = (FuncDeclaration **)param;
-
- if (*pf)
- {
- *pf = NULL;
- return 1; // ambiguous, done
- }
- else
- {
- *pf = f;
- return 0;
- }
- }
- };
- FuncDeclaration *result = NULL;
- overloadApply(this, &result, &ParamUnique::fp);
- return result;
-}
-
-/********************************************
- * Find function in overload list that exactly matches t.
- */
-
-FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t)
-{
- struct ParamExact
- {
- Type *t; // type to match
- FuncDeclaration *f; // return value
-
- static int fp(void *param, Dsymbol *s)
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (!f)
- return 0;
- ParamExact *p = (ParamExact *)param;
- Type *t = p->t;
-
- if (t->equals(f->type))
- {
- p->f = f;
- return 1;
- }
-
- /* Allow covariant matches, as long as the return type
- * is just a const conversion.
- * This allows things like pure functions to match with an impure function type.
- */
- if (t->ty == Tfunction)
- { TypeFunction *tf = (TypeFunction *)f->type;
- if (tf->covariant(t) == 1 &&
- tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst)
- {
- p->f = f;
- return 1;
- }
- }
- return 0;
- }
- };
- ParamExact p;
- p.t = t;
- p.f = NULL;
- overloadApply(this, &p, &ParamExact::fp);
- return p.f;
-}
-
-void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod)
-{
- bool bothMutable = ((lhsMod & rhsMod) == 0);
- bool sharedMismatch = ((lhsMod ^ rhsMod) & MODshared) != 0;
- bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODshared);
-
- if (lhsMod & MODshared)
- buf->writestring("shared ");
- else if (sharedMismatch && !(lhsMod & MODimmutable))
- buf->writestring("non-shared ");
-
- if (bothMutable && sharedMismatchOnly)
- { }
- else if (lhsMod & MODimmutable)
- buf->writestring("immutable ");
- else if (lhsMod & MODconst)
- buf->writestring("const ");
- else if (lhsMod & MODwild)
- buf->writestring("inout ");
- else
- buf->writestring("mutable ");
-}
-
-/********************************************
- * Find function in overload list that matches to the 'this' modifier.
- * There's four result types.
- *
- * 1. If the 'tthis' matches only one candidate, it's an "exact match".
- * Returns the function and 'hasOverloads' is set to false.
- * eg. If 'tthis" is mutable and there's only one mutable method.
- * 2. If there's two or more match candidates, but a candidate function will be
- * a "better match".
- * Returns the better match function but 'hasOverloads' is set to true.
- * eg. If 'tthis' is mutable, and there's both mutable and const methods,
- * the mutable method will be a better match.
- * 3. If there's two or more match candidates, but there's no better match,
- * Returns NULL and 'hasOverloads' is set to true to represent "ambiguous match".
- * eg. If 'tthis' is mutable, and there's two or more mutable methods.
- * 4. If there's no candidates, it's "no match" and returns NULL with error report.
- * e.g. If 'tthis' is const but there's no const methods.
- */
-FuncDeclaration *FuncDeclaration::overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads)
-{
- //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- struct ParamMod
- {
- Match *m;
- Type *tthis;
-
- static int fp(void *param, Dsymbol *s)
- {
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- return ((ParamMod *)param)->fp(fd);
- return 0;
- }
- int fp(FuncDeclaration *f)
- {
- if (f == m->lastf) // skip duplicates
- return 0;
-
- m->anyf = f;
- TypeFunction *tf = f->type->toTypeFunction();
- //printf("tf = %s\n", tf->toChars());
-
- MATCH match;
- if (tthis) // non-static functions are preferred than static ones
- {
- if (f->needThis())
- match = f->isCtorDeclaration() ? MATCHexact : MODmethodConv(tthis->mod, tf->mod);
- else
- match = MATCHconst; // keep static funciton in overload candidates
- }
- else // static functions are preferred than non-static ones
- {
- if (f->needThis())
- match = MATCHconvert;
- else
- match = MATCHexact;
- }
- if (match != MATCHnomatch)
- {
- if (match > m->last) goto LfIsBetter;
- if (match < m->last) goto LlastIsBetter;
-
- /* See if one of the matches overrides the other.
- */
- if (m->lastf->overrides(f)) goto LlastIsBetter;
- if (f->overrides(m->lastf)) goto LfIsBetter;
-
- //printf("\tambiguous\n");
- m->nextf = f;
- m->count++;
- return 0;
-
- LlastIsBetter:
- //printf("\tlastbetter\n");
- m->count++; // count up
- return 0;
-
- LfIsBetter:
- //printf("\tisbetter\n");
- if (m->last <= MATCHconvert)
- {
- // clear last secondary matching
- m->nextf = NULL;
- m->count = 0;
- }
- m->last = match;
- m->lastf = f;
- m->count++; // count up
- return 0;
- }
- return 0;
- }
- };
- ParamMod p;
- p.m = &m;
- p.tthis = tthis;
- overloadApply(this, &p, &ParamMod::fp);
-
- if (m.count == 1) // exact match
- {
- hasOverloads = false;
- }
- else if (m.count > 1) // better or ambiguous match
- {
- hasOverloads = true;
- }
- else // no match
- {
- hasOverloads = true;
- TypeFunction *tf = this->type->toTypeFunction();
- assert(tthis);
- assert(!MODimplicitConv(tthis->mod, tf->mod)); // modifier mismatch
- {
- OutBuffer thisBuf, funcBuf;
- MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
- MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
- ::error(loc, "%smethod %s is not callable using a %sobject",
- funcBuf.peekChars(), this->toPrettyChars(), thisBuf.peekChars());
- }
- }
-
- return m.lastf;
-}
-
-/********************************************
- * Returns true if function was declared
- * directly or indirectly in a unittest block
- */
-bool FuncDeclaration::inUnittest()
-{
- Dsymbol *f = this;
- do
- {
- if (f->isUnitTestDeclaration())
- return true;
- f = f->toParent();
- } while (f);
-
- return false;
-}
-
-/********************************************
- * find function template root in overload list
- */
-
-TemplateDeclaration *FuncDeclaration::findTemplateDeclRoot()
-{
- FuncDeclaration *f = this;
- while (f && f->overnext)
- {
- //printf("f->overnext = %p %s\n", f->overnext, f->overnext->toChars());
- TemplateDeclaration *td = f->overnext->isTemplateDeclaration();
- if (td)
- return td;
- f = f->overnext->isFuncDeclaration();
- }
- return NULL;
-}
-
-/*************************************
- * Determine partial specialization order of 'this' vs g.
- * This is very similar to TemplateDeclaration::leastAsSpecialized().
- * Returns:
- * match 'this' is at least as specialized as g
- * 0 g is more specialized than 'this'
- */
-
-MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g)
-{
- /* This works by calling g() with f()'s parameters, and
- * if that is possible, then f() is at least as specialized
- * as g() is.
- */
-
- TypeFunction *tf = type->toTypeFunction();
- TypeFunction *tg = g->type->toTypeFunction();
- size_t nfparams = tf->parameterList.length();
-
- /* If both functions have a 'this' pointer, and the mods are not
- * the same and g's is not const, then this is less specialized.
- */
- if (needThis() && g->needThis() && tf->mod != tg->mod)
- {
- if (isCtorDeclaration())
- {
- if (!MODimplicitConv(tg->mod, tf->mod))
- return MATCHnomatch;
- }
- else
- {
- if (!MODimplicitConv(tf->mod, tg->mod))
- return MATCHnomatch;
- }
- }
-
- /* Create a dummy array of arguments out of the parameters to f()
- */
- Expressions args;
- args.setDim(nfparams);
- for (size_t u = 0; u < nfparams; u++)
- {
- Parameter *p = tf->parameterList[u];
- Expression *e;
- if (p->storageClass & (STCref | STCout))
- {
- e = new IdentifierExp(Loc(), p->ident);
- e->type = p->type;
- }
- else
- e = p->type->defaultInitLiteral(Loc());
- args[u] = e;
- }
-
- MATCH m = (MATCH) tg->callMatch(NULL, &args, 1);
- if (m > MATCHnomatch)
- {
- /* A variadic parameter list is less specialized than a
- * non-variadic one.
- */
- if (tf->parameterList.varargs && !tg->parameterList.varargs)
- goto L1; // less specialized
-
- return m;
- }
- L1:
- return MATCHnomatch;
-}
-
-/// Walk through candidate template overloads and print them in the diagnostics.
-struct TemplateCandidateWalker
-{
- Loc loc;
- int numToDisplay; // max num of overloads to print (-v overrides this).
-
- /// Count template overloads.
- struct CountWalker
- {
- int numOverloads;
-
- static int fp(void *param, Dsymbol *)
- {
- CountWalker *p = (CountWalker *)param;
- ++(p->numOverloads);
- return 0;
- }
- };
-
- static int fp(void *param, Dsymbol *s)
- {
- TemplateDeclaration *t = s->isTemplateDeclaration();
- if (!t) return 0;
-
- TemplateCandidateWalker *p = (TemplateCandidateWalker *)param;
-
- ::errorSupplemental(t->loc, "%s", t->toPrettyChars());
-
- if (!global.params.verbose && --(p->numToDisplay) == 0 && t->overnext)
- {
- // Too many overloads to sensibly display.
- // Just show count of remaining overloads.
- CountWalker cw;
- cw.numOverloads = 0;
- overloadApply(t->overnext, &cw, &CountWalker::fp);
-
- if (cw.numOverloads > 0)
- ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
-
- return 1; // stop iterating
- }
-
- return 0;
- }
-};
-
-/// Walk through candidate template overloads and print them in the diagnostics.
-struct FuncCandidateWalker
-{
- Loc loc;
- int numToDisplay; // max num of overloads to print (-v overrides this).
-
- /// Count function overloads.
- struct CountWalker
- {
- int numOverloads;
-
- static int fp(void *param, Dsymbol *)
- {
- CountWalker *p = (CountWalker *)param;
- ++(p->numOverloads);
- return 0;
- }
- };
-
- static int fp(void *param, Dsymbol *s)
- {
- FuncDeclaration *fd = s->isFuncDeclaration();
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (fd)
- {
- if (fd->errors || fd->type->ty == Terror)
- return 0;
-
- TypeFunction *tf = (TypeFunction *)fd->type;
-
- ::errorSupplemental(fd->loc, "%s%s", fd->toPrettyChars(),
- parametersTypeToChars(tf->parameterList));
- }
- else
- {
- ::errorSupplemental(td->loc, "%s", td->toPrettyChars());
- }
-
- FuncCandidateWalker *p = (FuncCandidateWalker *)param;
- if (global.params.verbose || --(p->numToDisplay) != 0 || !fd)
- return 0;
-
- // Too many overloads to sensibly display.
- CountWalker cw;
- cw.numOverloads = 0;
- overloadApply(fd->overnext, &cw, &CountWalker::fp);
-
- if (cw.numOverloads > 0)
- ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
-
- return 1; // stop iterating
- }
-};
-
-/*******************************************
- * Given a symbol that could be either a FuncDeclaration or
- * a function template, resolve it to a function symbol.
- * loc instantiation location
- * sc instantiation scope
- * tiargs initial list of template arguments
- * tthis if !NULL, the 'this' pointer argument
- * fargs arguments to function
- * flags 1: do not issue error message on no match, just return NULL
- * 2: overloadResolve only
- */
-
-FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
- Objects *tiargs, Type *tthis, Expressions *fargs, int flags)
-{
- if (!s)
- return NULL; // no match
-
- if ((tiargs && arrayObjectIsError(tiargs)) ||
- (fargs && arrayObjectIsError((Objects *)fargs)))
- {
- return NULL;
- }
-
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- const char *failMessage = NULL;
- functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failMessage);
-
- if (m.last > MATCHnomatch && m.lastf)
- {
- if (m.count == 1) // exactly one match
- {
- if (!(flags & 1))
- m.lastf->functionSemantic();
- return m.lastf;
- }
- if ((flags & 2) && !tthis && m.lastf->needThis())
- {
- return m.lastf;
- }
- }
-
- /* Failed to find a best match.
- * Do nothing or print error.
- */
- if (m.last <= MATCHnomatch)
- {
- // error was caused on matched function
- if (m.count == 1)
- return m.lastf;
-
- // if do not print error messages
- if (flags & 1)
- return NULL; // no match
- }
-
- FuncDeclaration *fd = s->isFuncDeclaration();
- OverDeclaration *od = s->isOverDeclaration();
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td && td->funcroot)
- s = fd = td->funcroot;
-
- OutBuffer tiargsBuf;
- arrayObjectsToBuffer(&tiargsBuf, tiargs);
-
- OutBuffer fargsBuf;
- fargsBuf.writeByte('(');
- argExpTypesToCBuffer(&fargsBuf, fargs);
- fargsBuf.writeByte(')');
- if (tthis)
- tthis->modToBuffer(&fargsBuf);
-
- const int numOverloadsDisplay = 5; // sensible number to display
-
- if (!m.lastf && !(flags & 1)) // no match
- {
- if (td && !fd) // all of overloads are templates
- {
- ::error(loc, "%s %s.%s cannot deduce function from argument types !(%s)%s, candidates are:",
- td->kind(), td->parent->toPrettyChars(), td->ident->toChars(),
- tiargsBuf.peekChars(), fargsBuf.peekChars());
-
- // Display candidate templates (even if there are no multiple overloads)
- TemplateCandidateWalker tcw;
- tcw.loc = loc;
- tcw.numToDisplay = numOverloadsDisplay;
- overloadApply(td, &tcw, &TemplateCandidateWalker::fp);
- }
- else if (od)
- {
- ::error(loc, "none of the overloads of `%s` are callable using argument types !(%s)%s",
- od->ident->toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
- }
- else
- {
- assert(fd);
-
- bool hasOverloads = fd->overnext != NULL;
- TypeFunction *tf = fd->type->toTypeFunction();
- if (tthis && !MODimplicitConv(tthis->mod, tf->mod)) // modifier mismatch
- {
- OutBuffer thisBuf, funcBuf;
- MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
- MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
- if (hasOverloads)
- ::error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:",
- fd->ident->toChars(), thisBuf.peekChars());
- else
- ::error(loc, "%smethod `%s` is not callable using a %sobject",
- funcBuf.peekChars(), fd->toPrettyChars(), thisBuf.peekChars());
- }
- else
- {
- //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco);
- if (hasOverloads)
- ::error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:",
- fd->ident->toChars(), fargsBuf.peekChars());
- else
- {
- fd->error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
- fd->kind(), fd->toPrettyChars(), parametersTypeToChars(tf->parameterList),
- tf->modToChars(), fargsBuf.peekChars());
- if (failMessage)
- errorSupplemental(loc, failMessage);
- }
- }
-
- // Display candidate functions
- if (hasOverloads)
- {
- FuncCandidateWalker fcw;
- fcw.loc = loc;
- fcw.numToDisplay = numOverloadsDisplay;
- overloadApply(fd, &fcw, &FuncCandidateWalker::fp);
- }
- }
- }
- else if (m.nextf)
- {
- TypeFunction *tf1 = m.lastf->type->toTypeFunction();
- TypeFunction *tf2 = m.nextf->type->toTypeFunction();
- const char *lastprms = parametersTypeToChars(tf1->parameterList);
- const char *nextprms = parametersTypeToChars(tf2->parameterList);
- ::error(loc, "%s.%s called with argument types %s matches both:\n"
- "%s: %s%s\nand:\n%s: %s%s",
- s->parent->toPrettyChars(), s->ident->toChars(),
- fargsBuf.peekChars(),
- m.lastf->loc.toChars(), m.lastf->toPrettyChars(), lastprms,
- m.nextf->loc.toChars(), m.nextf->toPrettyChars(), nextprms);
- }
- return NULL;
-}
-
-/********************************
- * Labels are in a separate scope, one per function.
- */
-
-LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident)
-{ Dsymbol *s;
-
- if (!labtab)
- labtab = new DsymbolTable(); // guess we need one
-
- s = labtab->lookup(ident);
- if (!s)
- {
- s = new LabelDsymbol(ident);
- labtab->insert(s);
- }
- return (LabelDsymbol *)s;
-}
-
-/*****************************************
- * Determine lexical level difference from 'this' to nested function 'fd'.
- * Error if this cannot call fd.
- * Returns:
- * 0 same level
- * >0 decrease nesting by number
- * -1 increase nesting by 1 (fd is nested within 'this')
- * -2 error
- */
-
-int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd)
-{
- int level;
- Dsymbol *s;
- Dsymbol *fdparent;
-
- //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars());
- fdparent = fd->toParent2();
- if (fdparent == this)
- return -1;
- s = this;
- level = 0;
- while (fd != s && fdparent != s->toParent2())
- {
- //printf("\ts = %s, '%s'\n", s->kind(), s->toChars());
- FuncDeclaration *thisfd = s->isFuncDeclaration();
- if (thisfd)
- {
- if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof)
- goto Lerr;
- }
- else
- {
- AggregateDeclaration *thiscd = s->isAggregateDeclaration();
- if (thiscd)
- {
- /* AggregateDeclaration::isNested returns true only when
- * it has a hidden pointer.
- * But, calling the function belongs unrelated lexical scope
- * is still allowed inside typeof.
- *
- * struct Map(alias fun) {
- * typeof({ return fun(); }) RetType;
- * // No member function makes Map struct 'not nested'.
- * }
- */
- if (!thiscd->isNested() && !sc->intypeof)
- goto Lerr;
- }
- else
- goto Lerr;
- }
-
- s = s->toParent2();
- assert(s);
- level++;
- }
- return level;
-
-Lerr:
- // Don't give error if in template constraint
- if (!(sc->flags & SCOPEconstraint))
- {
- const char *xstatic = isStatic() ? "static " : "";
- // better diagnostics for static functions
- ::error(loc, "%s%s %s cannot access frame of function %s",
- xstatic, kind(), toPrettyChars(), fd->toPrettyChars());
- return -2;
- }
- return 1;
-}
-
-const char *FuncDeclaration::toPrettyChars(bool QualifyTypes)
-{
- if (isMain())
- return "D main";
- else
- return Dsymbol::toPrettyChars(QualifyTypes);
-}
-
-/** for diagnostics, e.g. 'int foo(int x, int y) pure' */
-const char *FuncDeclaration::toFullSignature()
-{
- OutBuffer buf;
- functionToBufferWithIdent(type->toTypeFunction(), &buf, toChars());
- return buf.extractChars();
-}
-
-bool FuncDeclaration::isMain()
-{
- return ident == Id::main &&
- linkage != LINKc && !isMember() && !isNested();
-}
-
-bool FuncDeclaration::isCMain()
-{
- return ident == Id::main &&
- linkage == LINKc && !isMember() && !isNested();
-}
-
-bool FuncDeclaration::isWinMain()
-{
- //printf("FuncDeclaration::isWinMain() %s\n", toChars());
- return ident == Id::WinMain &&
- linkage != LINKc && !isMember();
-}
-
-bool FuncDeclaration::isDllMain()
-{
- return ident == Id::DllMain &&
- linkage != LINKc && !isMember();
-}
-
-bool FuncDeclaration::isExport() const
-{
- return protection.kind == Prot::export_;
-}
-
-bool FuncDeclaration::isImportedSymbol() const
-{
- //printf("isImportedSymbol()\n");
- //printf("protection = %d\n", protection);
- return (protection.kind == Prot::export_) && !fbody;
-}
-
-// Determine if function goes into virtual function pointer table
-
-bool FuncDeclaration::isVirtual()
-{
- if (toAliasFunc() != this)
- return toAliasFunc()->isVirtual();
-
- Dsymbol *p = toParent();
- return isMember() &&
- !(isStatic() || protection.kind == Prot::private_ || protection.kind == Prot::package_) &&
- p->isClassDeclaration() &&
- !(p->isInterfaceDeclaration() && isFinalFunc());
-}
-
-// Determine if a function is pedantically virtual
-
-bool FuncDeclaration::isVirtualMethod()
-{
- if (toAliasFunc() != this)
- return toAliasFunc()->isVirtualMethod();
-
- //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
- if (!isVirtual())
- return false;
- // If it's a final method, and does not override anything, then it is not virtual
- if (isFinalFunc() && foverrides.length == 0)
- {
- return false;
- }
- return true;
-}
-
-bool FuncDeclaration::isFinalFunc()
-{
- if (toAliasFunc() != this)
- return toAliasFunc()->isFinalFunc();
-
- ClassDeclaration *cd;
- return isMember() &&
- (Declaration::isFinal() ||
- ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal));
-}
-
-bool FuncDeclaration::isCodeseg() const
-{
- return true; // functions are always in the code segment
-}
-
-bool FuncDeclaration::isOverloadable()
-{
- return true; // functions can be overloaded
-}
-
-PURE FuncDeclaration::isPure()
-{
- //printf("FuncDeclaration::isPure() '%s'\n", toChars());
- TypeFunction *tf = type->toTypeFunction();
- if (flags & FUNCFLAGpurityInprocess)
- setImpure();
- if (tf->purity == PUREfwdref)
- tf->purityLevel();
- PURE purity = tf->purity;
- if (purity > PUREweak && isNested())
- purity = PUREweak;
- if (purity > PUREweak && needThis())
- {
- // The attribute of the 'this' reference affects purity strength
- if (type->mod & MODimmutable)
- ;
- else if (type->mod & (MODconst | MODwild) && purity >= PUREconst)
- purity = PUREconst;
- else
- purity = PUREweak;
- }
- tf->purity = purity;
- // ^ This rely on the current situation that every FuncDeclaration has a
- // unique TypeFunction.
- return purity;
-}
-
-PURE FuncDeclaration::isPureBypassingInference()
-{
- if (flags & FUNCFLAGpurityInprocess)
- return PUREfwdref;
- else
- return isPure();
-}
-
-/**************************************
- * The function is doing something impure,
- * so mark it as impure.
- * If there's a purity error, return true.
- */
-bool FuncDeclaration::setImpure()
-{
- if (flags & FUNCFLAGpurityInprocess)
- {
- flags &= ~FUNCFLAGpurityInprocess;
- if (fes)
- fes->func->setImpure();
- }
- else if (isPure())
- return true;
- return false;
-}
-
-bool FuncDeclaration::isSafe()
-{
- if (flags & FUNCFLAGsafetyInprocess)
- setUnsafe();
- return type->toTypeFunction()->trust == TRUSTsafe;
-}
-
-bool FuncDeclaration::isSafeBypassingInference()
-{
- return !(flags & FUNCFLAGsafetyInprocess) && isSafe();
-}
-
-bool FuncDeclaration::isTrusted()
-{
- if (flags & FUNCFLAGsafetyInprocess)
- setUnsafe();
- return type->toTypeFunction()->trust == TRUSTtrusted;
-}
-
-/**************************************
- * The function is doing something unsave,
- * so mark it as unsafe.
- * If there's a safe error, return true.
- */
-bool FuncDeclaration::setUnsafe()
-{
- if (flags & FUNCFLAGsafetyInprocess)
- {
- flags &= ~FUNCFLAGsafetyInprocess;
- type->toTypeFunction()->trust = TRUSTsystem;
- if (fes)
- fes->func->setUnsafe();
- }
- else if (isSafe())
- return true;
- return false;
-}
-
-bool FuncDeclaration::isNogc()
-{
- if (flags & FUNCFLAGnogcInprocess)
- setGC();
- return type->toTypeFunction()->isnogc;
-}
-
-bool FuncDeclaration::isNogcBypassingInference()
-{
- return !(flags & FUNCFLAGnogcInprocess) && isNogc();
-}
-
-/**************************************
- * The function is doing something that may allocate with the GC,
- * so mark it as not nogc (not no-how).
- * Returns:
- * true if function is marked as @nogc, meaning a user error occurred
- */
-bool FuncDeclaration::setGC()
-{
- if (flags & FUNCFLAGnogcInprocess)
- {
- flags &= ~FUNCFLAGnogcInprocess;
- type->toTypeFunction()->isnogc = false;
- if (fes)
- fes->func->setGC();
- }
- else if (isNogc())
- return true;
- return false;
-}
-
-/**************************************
- * Returns an indirect type one step from t.
- */
-
-Type *getIndirection(Type *t)
-{
- t = t->baseElemOf();
- if (t->ty == Tarray || t->ty == Tpointer)
- return t->nextOf()->toBasetype();
- if (t->ty == Taarray || t->ty == Tclass)
- return t;
- if (t->ty == Tstruct)
- return t->hasPointers() ? t : NULL; // TODO
-
- // should consider TypeDelegate?
- return NULL;
-}
-
-/**************************************
- * Returns true if memory reachable through a reference B to a value of type tb,
- * which has been constructed with a reference A to a value of type ta
- * available, can alias memory reachable from A based on the types involved
- * (either directly or via any number of indirections).
- *
- * Note that this relation is not symmetric in the two arguments. For example,
- * a const(int) reference can point to a pre-existing int, but not the other
- * way round.
- */
-bool traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool reversePass = false)
-{
- Type *source = ta;
- Type *target = tb;
- if (reversePass)
- {
- source = tb;
- target = ta;
- }
-
- if (source->constConv(target))
- return true;
- else if (target->ty == Tvoid && MODimplicitConv(source->mod, target->mod))
- return true;
-
- // No direct match, so try breaking up one of the types (starting with tb).
- Type *tbb = tb->toBasetype()->baseElemOf();
- if (tbb != tb)
- return traverseIndirections(ta, tbb, p, reversePass);
-
- // context date to detect circular look up
- struct Ctxt
- {
- Ctxt *prev;
- Type *type;
- };
- Ctxt *ctxt = (Ctxt *)p;
-
- if (tb->ty == Tclass || tb->ty == Tstruct)
- {
- for (Ctxt *c = ctxt; c; c = c->prev)
- if (tb == c->type) return false;
- Ctxt c;
- c.prev = ctxt;
- c.type = tb;
-
- AggregateDeclaration *sym = tb->toDsymbol(NULL)->isAggregateDeclaration();
- for (size_t i = 0; i < sym->fields.length; i++)
- {
- VarDeclaration *v = sym->fields[i];
- Type *tprmi = v->type->addMod(tb->mod);
- //printf("\ttb = %s, tprmi = %s\n", tb->toChars(), tprmi->toChars());
- if (traverseIndirections(ta, tprmi, &c, reversePass))
- return true;
- }
- }
- else if (tb->ty == Tarray || tb->ty == Taarray || tb->ty == Tpointer)
- {
- Type *tind = tb->nextOf();
- if (traverseIndirections(ta, tind, ctxt, reversePass))
- return true;
- }
- else if (tb->hasPointers())
- {
- // FIXME: function pointer/delegate types should be considered.
- return true;
- }
-
- // Still no match, so try breaking up ta if we have note done so yet.
- if (!reversePass)
- return traverseIndirections(tb, ta, ctxt, true);
-
- return false;
-}
-
-/********************************************
- * Returns true if the function return value has no indirection
- * which comes from the parameters.
- */
-
-bool FuncDeclaration::isolateReturn()
-{
- TypeFunction *tf = type->toTypeFunction();
- assert(tf->next);
-
- Type *treti = tf->next;
- treti = tf->isref ? treti : getIndirection(treti);
- if (!treti)
- return true; // target has no mutable indirection
- return parametersIntersect(treti);
-}
-
-/********************************************
- * Returns true if an object typed t can have indirections
- * which come from the parameters.
- */
-
-bool FuncDeclaration::parametersIntersect(Type *t)
-{
- assert(t);
- if (!isPureBypassingInference() || isNested())
- return false;
-
- TypeFunction *tf = type->toTypeFunction();
-
- //printf("parametersIntersect(%s) t = %s\n", tf->toChars(), t->toChars());
-
- size_t dim = tf->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = tf->parameterList[i];
- if (!fparam->type)
- continue;
- Type *tprmi = (fparam->storageClass & (STClazy | STCout | STCref))
- ? fparam->type : getIndirection(fparam->type);
- if (!tprmi)
- continue; // there is no mutable indirection
-
- //printf("\t[%d] tprmi = %d %s\n", i, tprmi->ty, tprmi->toChars());
- if (traverseIndirections(tprmi, t))
- return false;
- }
- if (AggregateDeclaration *ad = isCtorDeclaration() ? NULL : isThis())
- {
- Type *tthis = ad->getType()->addMod(tf->mod);
- //printf("\ttthis = %s\n", tthis->toChars());
- if (traverseIndirections(tthis, t))
- return false;
- }
-
- return true;
-}
-
-/****************************************
- * Determine if function needs a static frame pointer.
- * Returns:
- * `true` if function is really nested within other function.
- * Contracts:
- * If isNested() returns true, isThis() should return false.
- */
-bool FuncDeclaration::isNested()
-{
- FuncDeclaration *f = toAliasFunc();
- //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars());
- return ((f->storage_class & STCstatic) == 0) &&
- (f->linkage == LINKd) &&
- (f->toParent2()->isFuncDeclaration() != NULL);
-}
-
-/****************************************
- * Determine if function is a non-static member function
- * that has an implicit 'this' expression.
- * Returns:
- * The aggregate it is a member of, or null.
- * Contracts:
- * If isThis() returns true, isNested() should return false.
- */
-AggregateDeclaration *FuncDeclaration::isThis()
-{
- //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
- AggregateDeclaration *ad = (storage_class & STCstatic) ? NULL : isMember2();
- //printf("-FuncDeclaration::isThis() %p\n", ad);
- return ad;
-}
-
-bool FuncDeclaration::needThis()
-{
- //printf("FuncDeclaration::needThis() '%s'\n", toChars());
- return toAliasFunc()->isThis() != NULL;
-}
-
-bool FuncDeclaration::addPreInvariant()
-{
- AggregateDeclaration *ad = isThis();
- ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
- return (ad && !(cd && cd->isCPPclass()) &&
- global.params.useInvariants == CHECKENABLEon &&
- (protection.kind == Prot::protected_ || protection.kind == Prot::public_ || protection.kind == Prot::export_) &&
- !naked);
-}
-
-bool FuncDeclaration::addPostInvariant()
-{
- AggregateDeclaration *ad = isThis();
- ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
- return (ad && !(cd && cd->isCPPclass()) &&
- ad->inv &&
- global.params.useInvariants == CHECKENABLEon &&
- (protection.kind == Prot::protected_ || protection.kind == Prot::public_ || protection.kind == Prot::export_) &&
- !naked);
-}
-
-/**********************************
- * Generate a FuncDeclaration for a runtime library function.
- */
-
-FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, const char *name, StorageClass stc)
-{
- return genCfunc(fparams, treturn, Identifier::idPool(name), stc);
-}
-
-FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, Identifier *id, StorageClass stc)
-{
- FuncDeclaration *fd;
- TypeFunction *tf;
- Dsymbol *s;
- static DsymbolTable *st = NULL;
-
- //printf("genCfunc(name = '%s')\n", id->toChars());
- //printf("treturn\n\t"); treturn->print();
-
- // See if already in table
- if (!st)
- st = new DsymbolTable();
- s = st->lookup(id);
- if (s)
- {
- fd = s->isFuncDeclaration();
- assert(fd);
- assert(fd->type->nextOf()->equals(treturn));
- }
- else
- {
- tf = new TypeFunction(ParameterList(fparams), treturn, LINKc, stc);
- fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf);
- fd->protection = Prot(Prot::public_);
- fd->linkage = LINKc;
-
- st->insert(fd);
- }
- return fd;
-}
-
-/******************
- * Check parameters and return type of D main() function.
- * Issue error messages.
- */
-void FuncDeclaration::checkDmain()
-{
- TypeFunction *tf = type->toTypeFunction();
- const size_t nparams = tf->parameterList.length();
- bool argerr = false;
- if (nparams == 1)
- {
- Parameter *fparam0 = tf->parameterList[0];
- Type *t = fparam0->type->toBasetype();
- if (t->ty != Tarray ||
- t->nextOf()->ty != Tarray ||
- t->nextOf()->nextOf()->ty != Tchar ||
- fparam0->storageClass & (STCout | STCref | STClazy))
- {
- argerr = true;
- }
- }
-
- if (!tf->nextOf())
- error("must return int or void");
- else if (tf->nextOf()->ty != Tint32 && tf->nextOf()->ty != Tvoid)
- error("must return int or void, not %s", tf->nextOf()->toChars());
- else if (tf->parameterList.varargs || nparams >= 2 || argerr)
- error("parameters must be main() or main(string[] args)");
-}
-
-/***********************************************
- * Check all return statements for a function to verify that returning
- * using NRVO is possible.
- *
- * Returns:
- * `false` if the result cannot be returned by hidden reference.
- */
-bool FuncDeclaration::checkNRVO()
-{
- if (!nrvo_can || returns == NULL)
- return false;
-
- TypeFunction *tf = type->toTypeFunction();
- if (tf->isref)
- return false;
-
- for (size_t i = 0; i < returns->length; i++)
- {
- ReturnStatement *rs = (*returns)[i];
-
- if (VarExp *ve = rs->exp->isVarExp())
- {
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (!v || v->isOut() || v->isRef())
- return false;
- else if (nrvo_var == NULL)
- {
- // Variables in the data segment (e.g. globals, TLS or not),
- // parameters and closure variables cannot be NRVOed.
- if (v->isDataseg() || v->isParameter() || v->toParent2() != this)
- return false;
- //printf("Setting nrvo to %s\n", v->toChars());
- nrvo_var = v;
- }
- else if (nrvo_var != v)
- return false;
- }
- else //if (!exp->isLvalue()) // keep NRVO-ability
- return false;
- }
- return true;
-}
-
-const char *FuncDeclaration::kind() const
-{
- return generated ? "generated function" : "function";
-}
-
-/*********************************************
- * In the current function, we are calling 'this' function.
- * 1. Check to see if the current function can call 'this' function, issue error if not.
- * 2. If the current function is not the parent of 'this' function, then add
- * the current function to the list of siblings of 'this' function.
- * 3. If the current function is a literal, and it's accessing an uplevel scope,
- * then mark it as a delegate.
- * Returns true if error occurs.
- */
-bool FuncDeclaration::checkNestedReference(Scope *sc, Loc loc)
-{
- //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
-
- if (FuncLiteralDeclaration *fld = this->isFuncLiteralDeclaration())
- {
- if (fld->tok == TOKreserved)
- {
- fld->tok = TOKfunction;
- fld->vthis = NULL;
- }
- }
-
- if (!parent || parent == sc->parent)
- return false;
- if (ident == Id::require || ident == Id::ensure)
- return false;
- if (!isThis() && !isNested())
- return false;
-
- // The current function
- FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
- if (!fdthis)
- return false; // out of function scope
-
- Dsymbol *p = toParent2();
-
- // Function literals from fdthis to p must be delegates
- checkNestedRef(fdthis, p);
-
- if (isNested())
- {
- // The function that this function is in
- FuncDeclaration *fdv = p->isFuncDeclaration();
- if (!fdv)
- return false;
- if (fdv == fdthis)
- return false;
-
- //printf("this = %s in [%s]\n", this->toChars(), this->loc.toChars());
- //printf("fdv = %s in [%s]\n", fdv->toChars(), fdv->loc.toChars());
- //printf("fdthis = %s in [%s]\n", fdthis->toChars(), fdthis->loc.toChars());
-
- // Add this function to the list of those which called us
- if (fdthis != this)
- {
- bool found = false;
- for (size_t i = 0; i < siblingCallers.length; ++i)
- {
- if (siblingCallers[i] == fdthis)
- found = true;
- }
- if (!found)
- {
- //printf("\tadding sibling %s\n", fdthis->toPrettyChars());
- if (!sc->intypeof && !(sc->flags & SCOPEcompile))
- siblingCallers.push(fdthis);
- }
- }
-
- int lv = fdthis->getLevel(loc, sc, fdv);
- if (lv == -2)
- return true; // error
- if (lv == -1)
- return false; // downlevel call
- if (lv == 0)
- return false; // same level call
- // Uplevel call
- }
- return false;
-}
-
-/* For all functions between outerFunc and f, mark them as needing
- * a closure.
- */
-void markAsNeedingClosure(Dsymbol *f, FuncDeclaration *outerFunc)
-{
- for (Dsymbol *sx = f; sx && sx != outerFunc; sx = sx->parent)
- {
- FuncDeclaration *fy = sx->isFuncDeclaration();
- if (fy && fy->closureVars.length)
- {
- /* fy needs a closure if it has closureVars[],
- * because the frame pointer in the closure will be accessed.
- */
- fy->requiresClosure = true;
- }
- }
-}
-
-
-/* Given a nested function f inside a function outerFunc, check
- * if any sibling callers of f have escaped. If so, mark
- * all the enclosing functions as needing closures.
- * Return true if any closures were detected.
- * This is recursive: we need to check the callers of our siblings.
- * Note that nested functions can only call lexically earlier nested
- * functions, so loops are impossible.
- */
-bool checkEscapingSiblings(FuncDeclaration *f, FuncDeclaration *outerFunc, void *p = NULL)
-{
- struct PrevSibling
- {
- PrevSibling *p;
- FuncDeclaration *f;
- };
-
- PrevSibling ps;
- ps.p = (PrevSibling *)p;
- ps.f = f;
-
- //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f->toChars(), outerFunc->toChars());
- bool bAnyClosures = false;
- for (size_t i = 0; i < f->siblingCallers.length; ++i)
- {
- FuncDeclaration *g = f->siblingCallers[i];
- if (g->isThis() || g->tookAddressOf)
- {
- markAsNeedingClosure(g, outerFunc);
- bAnyClosures = true;
- }
-
- PrevSibling *prev = (PrevSibling *)p;
- while (1)
- {
- if (!prev)
- {
- bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
- break;
- }
- if (prev->f == g)
- break;
- prev = prev->p;
- }
- }
- //printf("\t%d\n", bAnyClosures);
- return bAnyClosures;
-}
-
-
-/*******************************
- * Look at all the variables in this function that are referenced
- * by nested functions, and determine if a closure needs to be
- * created for them.
- */
-
-bool FuncDeclaration::needsClosure()
-{
- /* Need a closure for all the closureVars[] if any of the
- * closureVars[] are accessed by a
- * function that escapes the scope of this function.
- * We take the conservative approach and decide that a function needs
- * a closure if it:
- * 1) is a virtual function
- * 2) has its address taken
- * 3) has a parent that escapes
- * 4) calls another nested function that needs a closure
- *
- * Note that since a non-virtual function can be called by
- * a virtual one, if that non-virtual function accesses a closure
- * var, the closure still has to be taken. Hence, we check for isThis()
- * instead of isVirtual(). (thanks to David Friedman)
- *
- * When the function returns a local struct or class, `requiresClosure`
- * is already set to `true` upon entering this function when the
- * struct/class refers to a local variable and a closure is needed.
- */
-
- //printf("FuncDeclaration::needsClosure() %s\n", toChars());
-
- if (requiresClosure)
- goto Lyes;
-
- for (size_t i = 0; i < closureVars.length; i++)
- {
- VarDeclaration *v = closureVars[i];
- //printf("\tv = %s\n", v->toChars());
-
- for (size_t j = 0; j < v->nestedrefs.length; j++)
- {
- FuncDeclaration *f = v->nestedrefs[j];
- assert(f != this);
-
- //printf("\t\tf = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf);
-
- /* Look to see if f escapes. We consider all parents of f within
- * this, and also all siblings which call f; if any of them escape,
- * so does f.
- * Mark all affected functions as requiring closures.
- */
- for (Dsymbol *s = f; s && s != this; s = s->parent)
- {
- FuncDeclaration *fx = s->isFuncDeclaration();
- if (!fx)
- continue;
- if (fx->isThis() || fx->tookAddressOf)
- {
- //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx->toChars(), fx->isVirtual(), fx->isThis(), fx->tookAddressOf);
-
- /* Mark as needing closure any functions between this and f
- */
- markAsNeedingClosure( (fx == f) ? fx->parent : fx, this);
-
- requiresClosure = true;
- }
-
- /* We also need to check if any sibling functions that
- * called us, have escaped. This is recursive: we need
- * to check the callers of our siblings.
- */
- if (checkEscapingSiblings(fx, this))
- requiresClosure = true;
-
- /* Bugzilla 12406: Iterate all closureVars to mark all descendant
- * nested functions that access to the closing context of this funciton.
- */
- }
- }
- }
- if (requiresClosure)
- goto Lyes;
-
- return false;
-
-Lyes:
- //printf("\tneeds closure\n");
- return true;
-}
-
-/***********************************************
- * Check that the function contains any closure.
- * If it's @nogc, report suitable errors.
- * This is mostly consistent with FuncDeclaration::needsClosure().
- *
- * Returns:
- * true if any errors occur.
- */
-bool FuncDeclaration::checkClosure()
-{
- if (!needsClosure())
- return false;
-
- if (setGC())
- {
- error("is @nogc yet allocates closures with the GC");
- if (global.gag) // need not report supplemental errors
- return true;
- }
- else
- {
- printGCUsage(loc, "using closure causes GC allocation");
- return false;
- }
-
- FuncDeclarations a;
- for (size_t i = 0; i < closureVars.length; i++)
- {
- VarDeclaration *v = closureVars[i];
-
- for (size_t j = 0; j < v->nestedrefs.length; j++)
- {
- FuncDeclaration *f = v->nestedrefs[j];
- assert(f != this);
-
- for (Dsymbol *s = f; s && s != this; s = s->parent)
- {
- FuncDeclaration *fx = s->isFuncDeclaration();
- if (!fx)
- continue;
- if (fx->isThis() || fx->tookAddressOf)
- goto Lfound;
- if (checkEscapingSiblings(fx, this))
- goto Lfound;
- }
- continue;
-
- Lfound:
- for (size_t k = 0; ; k++)
- {
- if (k == a.length)
- {
- a.push(f);
- ::errorSupplemental(f->loc, "%s closes over variable %s at %s",
- f->toPrettyChars(), v->toChars(), v->loc.toChars());
- break;
- }
- if (a[k] == f)
- break;
- }
- continue;
- }
- }
-
- return true;
-}
-
-/***********************************************
- * Determine if function's variables are referenced by a function
- * nested within it.
- */
-
-bool FuncDeclaration::hasNestedFrameRefs()
-{
- if (closureVars.length)
- return true;
-
- /* If a virtual function has contracts, assume its variables are referenced
- * by those contracts, even if they aren't. Because they might be referenced
- * by the overridden or overriding function's contracts.
- * This can happen because frequire and fensure are implemented as nested functions,
- * and they can be called directly by an overriding function and the overriding function's
- * context had better match, or Bugzilla 7335 will bite.
- */
- if (fdrequire || fdensure)
- return true;
-
- if (foverrides.length && isVirtualMethod())
- {
- for (size_t i = 0; i < foverrides.length; i++)
- {
- FuncDeclaration *fdv = foverrides[i];
- if (fdv->hasNestedFrameRefs())
- return true;
- }
- }
-
- return false;
-}
-
-/*********************************************
- * Return the function's parameter list, and whether
- * it is variadic or not.
- */
-
-ParameterList FuncDeclaration::getParameterList()
-{
- if (type)
- {
- TypeFunction *fdtype = type->toTypeFunction();
- return fdtype->parameterList;
- }
-
- return ParameterList();
-}
-
-
-/****************************** FuncAliasDeclaration ************************/
-
-// Used as a way to import a set of functions from another scope into this one.
-
-FuncAliasDeclaration::FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads)
- : FuncDeclaration(funcalias->loc, funcalias->endloc, ident,
- funcalias->storage_class, funcalias->type)
-{
- assert(funcalias != this);
- this->funcalias = funcalias;
-
- this->hasOverloads = hasOverloads;
- if (hasOverloads)
- {
- if (FuncAliasDeclaration *fad = funcalias->isFuncAliasDeclaration())
- this->hasOverloads = fad->hasOverloads;
- }
- else
- { // for internal use
- assert(!funcalias->isFuncAliasDeclaration());
- this->hasOverloads = false;
- }
- userAttribDecl = funcalias->userAttribDecl;
-}
-
-const char *FuncAliasDeclaration::kind() const
-{
- return "function alias";
-}
-
-FuncDeclaration *FuncAliasDeclaration::toAliasFunc()
-{
- return funcalias->toAliasFunc();
-}
-
-
-/****************************** FuncLiteralDeclaration ************************/
-
-FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type,
- TOK tok, ForeachStatement *fes, Identifier *id)
- : FuncDeclaration(loc, endloc, NULL, STCundefined, type)
-{
- this->ident = id ? id : Id::empty;
- this->tok = tok;
- this->fes = fes;
- this->treq = NULL;
- this->deferToObj = false;
- //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars());
-}
-
-Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
- assert(!s);
- FuncLiteralDeclaration *f = new FuncLiteralDeclaration(loc, endloc,
- type->syntaxCopy(), tok, fes, ident);
- f->treq = treq; // don't need to copy
- return FuncDeclaration::syntaxCopy(f);
-}
-
-bool FuncLiteralDeclaration::isNested()
-{
- //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
- return (tok != TOKfunction) && !isThis();
-}
-
-AggregateDeclaration *FuncLiteralDeclaration::isThis()
-{
- //printf("FuncLiteralDeclaration::isThis() '%s'\n", toChars());
- return tok == TOKdelegate ? FuncDeclaration::isThis() : NULL;
-}
-
-bool FuncLiteralDeclaration::isVirtual()
-{
- return false;
-}
-
-bool FuncLiteralDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool FuncLiteralDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/*******************************
- * Modify all expression type of return statements to tret.
- *
- * On function literals, return type may be modified based on the context type
- * after its semantic3 is done, in FuncExp::implicitCastTo.
- *
- * A function() dg = (){ return new B(); } // OK if is(B : A) == true
- *
- * If B to A conversion is convariant that requires offseet adjusting,
- * all return statements should be adjusted to return expressions typed A.
- */
-void FuncLiteralDeclaration::modifyReturns(Scope *sc, Type *tret)
-{
- class RetWalker : public StatementRewriteWalker
- {
- public:
- Scope *sc;
- Type *tret;
- FuncLiteralDeclaration *fld;
-
- void visit(ReturnStatement *s)
- {
- Expression *exp = s->exp;
- if (exp && !exp->type->equals(tret))
- {
- s->exp = exp->castTo(sc, tret);
- }
- }
- };
-
- if (semanticRun < PASSsemantic3done)
- return;
-
- if (fes)
- return;
-
- RetWalker w;
- w.sc = sc;
- w.tret = tret;
- w.fld = this;
- fbody->accept(&w);
-
- // Also update the inferred function type to match the new return type.
- // This is required so the code generator does not try to cast the
- // modified returns back to the original type.
- if (inferRetType && type->nextOf() != tret)
- type->toTypeFunction()->next = tret;
-}
-
-const char *FuncLiteralDeclaration::kind() const
-{
- return (tok != TOKfunction) ? "delegate" : "function";
-}
-
-const char *FuncLiteralDeclaration::toPrettyChars(bool QualifyTypes)
-{
- if (parent)
- {
- TemplateInstance *ti = parent->isTemplateInstance();
- if (ti)
- return ti->tempdecl->toPrettyChars(QualifyTypes);
- }
- return Dsymbol::toPrettyChars(QualifyTypes);
-}
-
-/********************************* CtorDeclaration ****************************/
-
-CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type)
- : FuncDeclaration(loc, endloc, Id::ctor, stc, type)
-{
- //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
-}
-
-Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- CtorDeclaration *f = new CtorDeclaration(loc, endloc, storage_class, type->syntaxCopy());
- return FuncDeclaration::syntaxCopy(f);
-}
-
-const char *CtorDeclaration::kind() const
-{
- return "constructor";
-}
-
-const char *CtorDeclaration::toChars()
-{
- return "this";
-}
-
-bool CtorDeclaration::isVirtual()
-{
- return false;
-}
-
-bool CtorDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool CtorDeclaration::addPostInvariant()
-{
- return (isThis() && vthis && global.params.useInvariants == CHECKENABLEon);
-}
-
-
-/********************************* PostBlitDeclaration ****************************/
-
-PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
- : FuncDeclaration(loc, endloc, id, stc, NULL)
-{
-}
-
-Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
- return FuncDeclaration::syntaxCopy(dd);
-}
-
-bool PostBlitDeclaration::overloadInsert(Dsymbol *)
-{
- return false; // cannot overload postblits
-}
-
-bool PostBlitDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool PostBlitDeclaration::addPostInvariant()
-{
- return (isThis() && vthis && global.params.useInvariants == CHECKENABLEon);
-}
-
-bool PostBlitDeclaration::isVirtual()
-{
- return false;
-}
-
-/********************************* DtorDeclaration ****************************/
-
-DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc)
- : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL)
-{
-}
-
-DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
- : FuncDeclaration(loc, endloc, id, stc, NULL)
-{
-}
-
-Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- DtorDeclaration *dd = new DtorDeclaration(loc, endloc, storage_class, ident);
- return FuncDeclaration::syntaxCopy(dd);
-}
-
-bool DtorDeclaration::overloadInsert(Dsymbol *)
-{
- return false; // cannot overload destructors
-}
-
-bool DtorDeclaration::addPreInvariant()
-{
- return (isThis() && vthis && global.params.useInvariants == CHECKENABLEon);
-}
-
-bool DtorDeclaration::addPostInvariant()
-{
- return false;
-}
-
-const char *DtorDeclaration::kind() const
-{
- return "destructor";
-}
-
-const char *DtorDeclaration::toChars()
-{
- return "~this";
-}
-
-bool DtorDeclaration::isVirtual()
-{
- // false so that dtor's don't get put into the vtbl[]
- return false;
-}
-
-/********************************* StaticCtorDeclaration ****************************/
-
-StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId("_staticCtor"), STCstatic | stc, NULL)
-{
-}
-
-StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId(name), STCstatic | stc, NULL)
-{
-}
-
-Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- StaticCtorDeclaration *scd = new StaticCtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(scd);
-}
-
-AggregateDeclaration *StaticCtorDeclaration::isThis()
-{
- return NULL;
-}
-
-bool StaticCtorDeclaration::isVirtual()
-{
- return false;
-}
-
-bool StaticCtorDeclaration::hasStaticCtorOrDtor()
-{
- return true;
-}
-
-bool StaticCtorDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool StaticCtorDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* SharedStaticCtorDeclaration ****************************/
-
-SharedStaticCtorDeclaration::SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : StaticCtorDeclaration(loc, endloc, "_sharedStaticCtor", stc)
-{
-}
-
-Dsymbol *SharedStaticCtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- SharedStaticCtorDeclaration *scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(scd);
-}
-
-/********************************* StaticDtorDeclaration ****************************/
-
-StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId("_staticDtor"), STCstatic | stc, NULL)
-{
- vgate = NULL;
-}
-
-StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId(name), STCstatic | stc, NULL)
-{
- vgate = NULL;
-}
-
-Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(sdd);
-}
-
-AggregateDeclaration *StaticDtorDeclaration::isThis()
-{
- return NULL;
-}
-
-bool StaticDtorDeclaration::isVirtual()
-{
- return false;
-}
-
-bool StaticDtorDeclaration::hasStaticCtorOrDtor()
-{
- return true;
-}
-
-bool StaticDtorDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool StaticDtorDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* SharedStaticDtorDeclaration ****************************/
-
-SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor", stc)
-{
-}
-
-Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(sdd);
-}
-
-/********************************* InvariantDeclaration ****************************/
-
-InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
- : FuncDeclaration(loc, endloc,
- id ? id : Identifier::generateId("__invariant"),
- stc, NULL)
-{
-}
-
-Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- InvariantDeclaration *id = new InvariantDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(id);
-}
-
-bool InvariantDeclaration::isVirtual()
-{
- return false;
-}
-
-bool InvariantDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool InvariantDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* UnitTestDeclaration ****************************/
-
-/*******************************
- * Generate unique unittest function Id so we can have multiple
- * instances per module.
- */
-
-static Identifier *unitTestId(Loc loc)
-{
- OutBuffer buf;
- buf.printf("__unittestL%u_", loc.linnum);
- return Identifier::generateId(buf.peekChars());
-}
-
-UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc)
- : FuncDeclaration(loc, endloc, unitTestId(loc), stc, NULL)
-{
- this->codedoc = codedoc;
-}
-
-Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- UnitTestDeclaration *utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
- return FuncDeclaration::syntaxCopy(utd);
-}
-
-AggregateDeclaration *UnitTestDeclaration::isThis()
-{
- return NULL;
-}
-
-bool UnitTestDeclaration::isVirtual()
-{
- return false;
-}
-
-bool UnitTestDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool UnitTestDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* NewDeclaration ****************************/
-
-NewDeclaration::NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams, VarArg varargs)
- : FuncDeclaration(loc, endloc, Id::classNew, STCstatic | stc, NULL)
-{
- this->parameters = fparams;
- this->varargs = varargs;
-}
-
-Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- NewDeclaration *f = new NewDeclaration(loc, endloc,
- storage_class, Parameter::arraySyntaxCopy(parameters), varargs);
- return FuncDeclaration::syntaxCopy(f);
-}
-
-const char *NewDeclaration::kind() const
-{
- return "allocator";
-}
-
-bool NewDeclaration::isVirtual()
-{
- return false;
-}
-
-bool NewDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool NewDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* DeleteDeclaration ****************************/
-
-DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams)
- : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic | stc, NULL)
-{
- this->parameters = fparams;
-}
-
-Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- DeleteDeclaration *f = new DeleteDeclaration(loc, endloc,
- storage_class, Parameter::arraySyntaxCopy(parameters));
- return FuncDeclaration::syntaxCopy(f);
-}
-
-const char *DeleteDeclaration::kind() const
-{
- return "deallocator";
-}
-
-bool DeleteDeclaration::isDelete()
-{
- return true;
-}
-
-bool DeleteDeclaration::isVirtual()
-{
- return false;
-}
-
-bool DeleteDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool DeleteDeclaration::addPostInvariant()
-{
- return false;
-}