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.c2752
1 files changed, 43 insertions, 2709 deletions
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
index 2f1d648..7a216a9 100644
--- a/gcc/d/dmd/func.c
+++ b/gcc/d/dmd/func.c
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * 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.
@@ -22,275 +22,20 @@
#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"
-#include "objc.h"
-Expression *addInvariant(AggregateDeclaration *ad, VarDeclaration *vthis);
-bool checkReturnEscape(Scope *sc, Expression *e, bool gag);
-bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag);
bool checkNestedRef(Dsymbol *s, Dsymbol *p);
-Statement *semantic(Statement *s, Scope *sc);
-void semantic(Catch *c, Scope *sc);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-Expression *semantic(Expression *e, Scope *sc);
int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
TypeIdentifier *getThrowable();
-void MODtoBuffer(OutBuffer *buf, MOD mod);
-char *MODtoChars(MOD mod);
bool MODimplicitConv(MOD modfrom, MOD modto);
MATCH MODmethodConv(MOD modfrom, MOD modto);
-void allocFieldinit(Scope *sc, size_t dim);
-void freeFieldinit(Scope *sc);
-Objc *objc();
-
-
-/* A visitor to walk entire statements and provides ability to replace any sub-statements.
- */
-class StatementRewriteWalker : public Visitor
-{
- /* Point the currently visited statement.
- * By using replaceCurrent() method, you can replace AST during walking.
- */
- Statement **ps;
-public:
- void visitStmt(Statement *&s) { ps = &s; s->accept(this); }
- void replaceCurrent(Statement *s) { *ps = s; }
-
- void visit(ErrorStatement *) { }
- void visit(PeelStatement *s)
- {
- if (s->s)
- visitStmt(s->s);
- }
- void visit(ExpStatement *) { }
- void visit(DtorExpStatement *) { }
- void visit(CompileStatement *) { }
- void visit(CompoundStatement *s)
- {
- if (s->statements && s->statements->length)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- {
- if ((*s->statements)[i])
- visitStmt((*s->statements)[i]);
- }
- }
- }
- void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
- void visit(UnrolledLoopStatement *s)
- {
- if (s->statements && s->statements->length)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- {
- if ((*s->statements)[i])
- visitStmt((*s->statements)[i]);
- }
- }
- }
- void visit(ScopeStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(WhileStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(DoStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(ForStatement *s)
- {
- if (s->_init)
- visitStmt(s->_init);
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(ForeachStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(ForeachRangeStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(IfStatement *s)
- {
- if (s->ifbody)
- visitStmt(s->ifbody);
- if (s->elsebody)
- visitStmt(s->elsebody);
- }
- void visit(ConditionalStatement *) { }
- void visit(PragmaStatement *) { }
- void visit(StaticAssertStatement *) { }
- void visit(SwitchStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(CaseStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(CaseRangeStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(DefaultStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(GotoDefaultStatement *) { }
- void visit(GotoCaseStatement *) { }
- void visit(SwitchErrorStatement *) { }
- void visit(ReturnStatement *) { }
- void visit(BreakStatement *) { }
- void visit(ContinueStatement *) { }
- void visit(SynchronizedStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(WithStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(TryCatchStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- if (s->catches && s->catches->length)
- {
- for (size_t i = 0; i < s->catches->length; i++)
- {
- Catch *c = (*s->catches)[i];
- if (c && c->handler)
- visitStmt(c->handler);
- }
- }
- }
- void visit(TryFinallyStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- if (s->finalbody)
- visitStmt(s->finalbody);
- }
- void visit(ScopeGuardStatement *) { }
- void visit(ThrowStatement *) { }
- void visit(DebugStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(GotoStatement *) { }
- void visit(LabelStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(AsmStatement *) { }
- void visit(ImportStatement *) { }
-};
-
-/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
- */
-class NrvoWalker : public StatementRewriteWalker
-{
-public:
- FuncDeclaration *fd;
- Scope *sc;
-
- void visit(ReturnStatement *s)
- {
- // See if all returns are instead to be replaced with a goto returnLabel;
- if (fd->returnLabel)
- {
- /* Rewrite:
- * return exp;
- * as:
- * vresult = exp; goto Lresult;
- */
- GotoStatement *gs = new GotoStatement(s->loc, Id::returnLabel);
- gs->label = fd->returnLabel;
-
- Statement *s1 = gs;
- if (s->exp)
- s1 = new CompoundStatement(s->loc, new ExpStatement(s->loc, s->exp), gs);
-
- replaceCurrent(s1);
- }
- }
- void visit(TryFinallyStatement *s)
- {
- DtorExpStatement *des;
- if (fd->nrvo_can &&
- s->finalbody && (des = s->finalbody->isDtorExpStatement()) != NULL &&
- fd->nrvo_var == des->var)
- {
- if (!(global.params.useExceptions && ClassDeclaration::throwable))
- {
- /* Don't need to call destructor at all, since it is nrvo
- */
- replaceCurrent(s->_body);
- s->_body->accept(this);
- return;
- }
-
- /* Normally local variable dtors are called regardless exceptions.
- * But for nrvo_var, its dtor should be called only when exception is thrown.
- *
- * Rewrite:
- * try { s->body; } finally { nrvo_var->edtor; }
- * // equivalent with:
- * // s->body; scope(exit) nrvo_var->edtor;
- * as:
- * try { s->body; } catch(Throwable __o) { nrvo_var->edtor; throw __o; }
- * // equivalent with:
- * // s->body; scope(failure) nrvo_var->edtor;
- */
- Statement *sexception = new DtorExpStatement(Loc(), fd->nrvo_var->edtor, fd->nrvo_var);
- Identifier *id = Identifier::generateId("__o");
-
- Statement *handler = new PeelStatement(sexception);
- if (blockExit(sexception, fd, false) & BEfallthru)
- {
- ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
- ts->internalThrow = true;
- handler = new CompoundStatement(Loc(), handler, ts);
- }
-
- Catches *catches = new Catches();
- Catch *ctch = new Catch(Loc(), getThrowable(), id, handler);
- ctch->internalCatch = true;
- ::semantic(ctch, sc); // Run semantic to resolve identifier '__o'
- catches->push(ctch);
-
- Statement *s2 = new TryCatchStatement(Loc(), s->_body, catches);
- replaceCurrent(s2);
- s2->accept(this);
- }
- else
- StatementRewriteWalker::visit(s);
- }
-};
/***********************************************************
* Tuple of result identifier (possibly null) and statement.
@@ -416,69 +161,8 @@ Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
return f;
}
-/**********************************
- * Decide if attributes for this function can be inferred from examining
- * the function body.
- * Returns:
- * true if can
- */
-static bool canInferAttributes(FuncDeclaration *fd, Scope *sc)
-{
- if (!fd->fbody)
- return false;
-
- if (fd->isVirtualMethod())
- return false; // since they may be overridden
-
- if (sc->func &&
- /********** this is for backwards compatibility for the moment ********/
- (!fd->isMember() || (sc->func->isSafeBypassingInference() && !fd->isInstantiated())))
- return true;
-
- if (fd->isFuncLiteralDeclaration() || // externs are not possible with literals
- (fd->storage_class & STCinference) || // do attribute inference
- (fd->inferRetType && !fd->isCtorDeclaration()))
- return true;
-
- if (fd->isInstantiated())
- {
- TemplateInstance *ti = fd->parent->isTemplateInstance();
- if (ti == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == fd->ident)
- return true;
- }
-
- return false;
-}
-
-/*****************************************
- * Initialize for inferring the attributes of this function.
- */
-static void initInferAttributes(FuncDeclaration *fd)
-{
- //printf("initInferAttributes() for %s\n", toPrettyChars());
- TypeFunction *tf = fd->type->toTypeFunction();
- if (tf->purity == PUREimpure) // purity not specified
- fd->flags |= FUNCFLAGpurityInprocess;
-
- if (tf->trust == TRUSTdefault)
- fd->flags |= FUNCFLAGsafetyInprocess;
-
- if (!tf->isnothrow)
- fd->flags |= FUNCFLAGnothrowInprocess;
-
- if (!tf->isnogc)
- fd->flags |= FUNCFLAGnogcInprocess;
-
- if (!fd->isVirtual() || fd->introducing)
- fd->flags |= FUNCFLAGreturnInprocess;
-
- // Initialize for inferring STCscope
- if (global.params.vsafe)
- fd->flags |= FUNCFLAGinferScope;
-}
-
// Returns true if a contract can appear without a function body.
-static bool allowsContractWithoutBody(FuncDeclaration *funcdecl)
+bool allowsContractWithoutBody(FuncDeclaration *funcdecl)
{
assert(!funcdecl->fbody);
@@ -499,824 +183,6 @@ static bool allowsContractWithoutBody(FuncDeclaration *funcdecl)
return true;
}
-// Do the semantic analysis on the external interface to the function.
-
-void FuncDeclaration::semantic(Scope *sc)
-{
- TypeFunction *f;
- AggregateDeclaration *ad;
- InterfaceDeclaration *id;
-
- if (semanticRun != PASSinit && isFuncLiteralDeclaration())
- {
- /* Member functions that have return types that are
- * forward references can have semantic() run more than
- * once on them.
- * See test\interface2.d, test20
- */
- return;
- }
-
- if (semanticRun >= PASSsemanticdone)
- return;
- assert(semanticRun <= PASSsemantic);
- semanticRun = PASSsemantic;
-
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- if (!sc || errors)
- return;
-
- parent = sc->parent;
- Dsymbol *parent = toParent();
-
- foverrides.setDim(0); // reset in case semantic() is being retried for this function
-
- storage_class |= sc->stc & ~STCref;
- ad = isThis();
- // Don't nest structs b/c of generated methods which should not access the outer scopes.
- // https://issues.dlang.org/show_bug.cgi?id=16627
- if (ad && !generated)
- {
- storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized);
- ad->makeNested();
- }
- if (sc->func)
- storage_class |= sc->func->storage_class & STCdisable;
- // Remove prefix storage classes silently.
- if ((storage_class & STC_TYPECTOR) && !(ad || isNested()))
- storage_class &= ~STC_TYPECTOR;
-
- //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", storage_class, sc->stc, Declaration::isFinal());
-
- FuncLiteralDeclaration *fld = isFuncLiteralDeclaration();
- if (fld && fld->treq)
- {
- Type *treq = fld->treq;
- assert(treq->nextOf()->ty == Tfunction);
- if (treq->ty == Tdelegate)
- fld->tok = TOKdelegate;
- else if (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)
- fld->tok = TOKfunction;
- else
- assert(0);
- linkage = treq->nextOf()->toTypeFunction()->linkage;
- }
- else
- linkage = sc->linkage;
- inlining = sc->inlining;
- protection = sc->protection;
- userAttribDecl = sc->userAttribDecl;
-
- if (!originalType)
- originalType = type->syntaxCopy();
- if (type->ty != Tfunction)
- {
- if (type->ty != Terror)
- {
- error("%s must be a function instead of %s", toChars(), type->toChars());
- type = Type::terror;
- }
- errors = true;
- return;
- }
- if (!type->deco)
- {
- sc = sc->push();
- sc->stc |= storage_class & (STCdisable | STCdeprecated); // forward to function type
- TypeFunction *tf = type->toTypeFunction();
-
- if (sc->func)
- {
- /* If the nesting parent is pure without inference,
- * then this function defaults to pure too.
- *
- * auto foo() pure {
- * auto bar() {} // become a weak purity funciton
- * class C { // nested class
- * auto baz() {} // become a weak purity funciton
- * }
- *
- * static auto boo() {} // typed as impure
- * // Even though, boo cannot call any impure functions.
- * // See also Expression::checkPurity().
- * }
- */
- if (tf->purity == PUREimpure && (isNested() || isThis()))
- {
- FuncDeclaration *fd = NULL;
- for (Dsymbol *p = toParent2(); p; p = p->toParent2())
- {
- if (AggregateDeclaration *adx = p->isAggregateDeclaration())
- {
- if (adx->isNested())
- continue;
- break;
- }
- if ((fd = p->isFuncDeclaration()) != NULL)
- break;
- }
-
- /* If the parent's purity is inferred, then this function's purity needs
- * to be inferred first.
- */
- if (fd && fd->isPureBypassingInference() >= PUREweak &&
- !isInstantiated())
- {
- tf->purity = PUREfwdref; // default to pure
- }
- }
- }
-
- if (tf->isref) sc->stc |= STCref;
- if (tf->isscope) sc->stc |= STCscope;
- if (tf->isnothrow) sc->stc |= STCnothrow;
- if (tf->isnogc) sc->stc |= STCnogc;
- if (tf->isproperty) sc->stc |= STCproperty;
- if (tf->purity == PUREfwdref) sc->stc |= STCpure;
- if (tf->trust != TRUSTdefault)
- sc->stc &= ~(STCsafe | STCsystem | STCtrusted);
- if (tf->trust == TRUSTsafe) sc->stc |= STCsafe;
- if (tf->trust == TRUSTsystem) sc->stc |= STCsystem;
- if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted;
-
- if (isCtorDeclaration())
- {
- sc->flags |= SCOPEctor;
-
- Type *tret = ad->handleType();
- assert(tret);
- tret = tret->addStorageClass(storage_class | sc->stc);
- tret = tret->addMod(type->mod);
- tf->next = tret;
-
- if (ad->isStructDeclaration())
- sc->stc |= STCref;
- }
-
- // 'return' on a non-static class member function implies 'scope' as well
- if (ad && ad->isClassDeclaration() && (tf->isreturn || sc->stc & STCreturn) && !(sc->stc & STCstatic))
- sc->stc |= STCscope;
-
- // If 'this' has no pointers, remove 'scope' as it has no meaning
- if (sc->stc & STCscope && ad && ad->isStructDeclaration() && !ad->type->hasPointers())
- {
- sc->stc &= ~STCscope;
- tf->isscope = false;
- }
-
- sc->linkage = linkage;
-
- if (!tf->isNaked() && !(isThis() || isNested()))
- {
- OutBuffer buf;
- MODtoBuffer(&buf, tf->mod);
- error("without 'this' cannot be %s", buf.peekChars());
- tf->mod = 0; // remove qualifiers
- }
-
- /* Apply const, immutable, wild and shared storage class
- * to the function type. Do this before type semantic.
- */
- StorageClass stc = storage_class;
- if (type->isImmutable())
- stc |= STCimmutable;
- if (type->isConst())
- stc |= STCconst;
- if (type->isShared() || storage_class & STCsynchronized)
- stc |= STCshared;
- if (type->isWild())
- stc |= STCwild;
- switch (stc & STC_TYPECTOR)
- {
- case STCimmutable:
- case STCimmutable | STCconst:
- case STCimmutable | STCwild:
- case STCimmutable | STCwild | STCconst:
- case STCimmutable | STCshared:
- case STCimmutable | STCshared | STCconst:
- case STCimmutable | STCshared | STCwild:
- case STCimmutable | STCshared | STCwild | STCconst:
- // Don't use immutableOf(), as that will do a merge()
- type = type->makeImmutable();
- break;
-
- case STCconst:
- type = type->makeConst();
- break;
-
- case STCwild:
- type = type->makeWild();
- break;
-
- case STCwild | STCconst:
- type = type->makeWildConst();
- break;
-
- case STCshared:
- type = type->makeShared();
- break;
-
- case STCshared | STCconst:
- type = type->makeSharedConst();
- break;
-
- case STCshared | STCwild:
- type = type->makeSharedWild();
- break;
-
- case STCshared | STCwild | STCconst:
- type = type->makeSharedWildConst();
- break;
-
- case 0:
- break;
-
- default:
- assert(0);
- }
-
- type = type->semantic(loc, sc);
- sc = sc->pop();
- }
- if (type->ty != Tfunction)
- {
- if (type->ty != Terror)
- {
- error("%s must be a function instead of %s", toChars(), type->toChars());
- type = Type::terror;
- }
- errors = true;
- return;
- }
- else
- {
- // Merge back function attributes into 'originalType'.
- // It's used for mangling, ddoc, and json output.
- TypeFunction *tfo = originalType->toTypeFunction();
- TypeFunction *tfx = type->toTypeFunction();
- tfo->mod = tfx->mod;
- tfo->isscope = tfx->isscope;
- tfo->isscopeinferred = tfx->isscopeinferred;
- tfo->isref = tfx->isref;
- tfo->isnothrow = tfx->isnothrow;
- tfo->isnogc = tfx->isnogc;
- tfo->isproperty = tfx->isproperty;
- tfo->purity = tfx->purity;
- tfo->trust = tfx->trust;
-
- storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
- }
-
- f = (TypeFunction *)type;
-
- if ((storage_class & STCauto) && !f->isref && !inferRetType)
- error("storage class 'auto' has no effect if return type is not inferred");
- /* Functions can only be 'scope' if they have a 'this'
- */
- if (f->isscope && !isNested() && !ad)
- {
- error("functions cannot be scope");
- }
-
- if (f->isreturn && !needThis() && !isNested())
- {
- /* Non-static nested functions have a hidden 'this' pointer to which
- * the 'return' applies
- */
- error("static member has no 'this' to which 'return' can apply");
- }
-
- if (isAbstract() && !isVirtual())
- {
- const char *sfunc;
- if (isStatic())
- sfunc = "static";
- else if (protection.kind == Prot::private_ || protection.kind == Prot::package_)
- sfunc = protectionToChars(protection.kind);
- else
- sfunc = "non-virtual";
- error("%s functions cannot be abstract", sfunc);
- }
-
- if (isOverride() && !isVirtual())
- {
- Prot::Kind kind = prot().kind;
- if ((kind == Prot::private_ || kind == Prot::package_) && isMember())
- error("%s method is not virtual and cannot override", protectionToChars(kind));
- else
- error("cannot override a non-virtual function");
- }
-
- if (isAbstract() && isFinalFunc())
- error("cannot be both final and abstract");
-
- id = parent->isInterfaceDeclaration();
- if (id)
- {
- storage_class |= STCabstract;
-
- if (isCtorDeclaration() ||
- isPostBlitDeclaration() ||
- isDtorDeclaration() ||
- isInvariantDeclaration() ||
- isNewDeclaration() || isDelete())
- error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id->toChars());
- if (fbody && isVirtual())
- error("function body only allowed in final functions in interface %s", id->toChars());
- }
-
- if (UnionDeclaration *ud = parent->isUnionDeclaration())
- {
- if (isPostBlitDeclaration() ||
- isDtorDeclaration() ||
- isInvariantDeclaration())
- error("destructors, postblits and invariants are not allowed in union %s", ud->toChars());
- }
-
- if (parent->isStructDeclaration())
- {
- if (isCtorDeclaration())
- {
- goto Ldone;
- }
- }
-
- if (ClassDeclaration *cd = parent->isClassDeclaration())
- {
- if (isCtorDeclaration())
- {
- goto Ldone;
- }
-
- if (storage_class & STCabstract)
- cd->isabstract = ABSyes;
-
- // if static function, do not put in vtbl[]
- if (!isVirtual())
- {
- //printf("\tnot virtual\n");
- goto Ldone;
- }
- // Suppress further errors if the return type is an error
- if (type->nextOf() == Type::terror)
- goto Ldone;
-
- bool may_override = false;
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *b = (*cd->baseclasses)[i];
- ClassDeclaration *cbd = b->type->toBasetype()->isClassHandle();
- if (!cbd)
- continue;
- for (size_t j = 0; j < cbd->vtbl.length; j++)
- {
- FuncDeclaration *f2 = cbd->vtbl[j]->isFuncDeclaration();
- if (!f2 || f2->ident != ident)
- continue;
- if (cbd->parent && cbd->parent->isTemplateInstance())
- {
- if (!f2->functionSemantic())
- goto Ldone;
- }
- may_override = true;
- }
- }
- if (may_override && type->nextOf() == NULL)
- {
- /* If same name function exists in base class but 'this' is auto return,
- * cannot find index of base class's vtbl[] to override.
- */
- error("return type inference is not supported if may override base class function");
- }
-
- /* Find index of existing function in base class's vtbl[] to override
- * (the index will be the same as in cd's current vtbl[])
- */
- int vi = cd->baseClass ? findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length)
- : -1;
-
- bool doesoverride = false;
- switch (vi)
- {
- case -1:
- Lintro:
- /* Didn't find one, so
- * This is an 'introducing' function which gets a new
- * slot in the vtbl[].
- */
-
- // Verify this doesn't override previous final function
- if (cd->baseClass)
- {
- Dsymbol *s = cd->baseClass->search(loc, ident);
- if (s)
- {
- FuncDeclaration *f2 = s->isFuncDeclaration();
- if (f2)
- {
- f2 = f2->overloadExactMatch(type);
- if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_)
- error("cannot override final function %s", f2->toPrettyChars());
- }
- }
- }
-
- /* These quirky conditions mimic what VC++ appears to do
- */
- if (global.params.mscoff && cd->isCPPclass() &&
- cd->baseClass && cd->baseClass->vtbl.length)
- {
- /* if overriding an interface function, then this is not
- * introducing and don't put it in the class vtbl[]
- */
- interfaceVirtual = overrideInterface();
- if (interfaceVirtual)
- {
- //printf("\tinterface function %s\n", toChars());
- cd->vtblFinal.push(this);
- goto Linterfaces;
- }
- }
-
- if (isFinalFunc())
- {
- // Don't check here, as it may override an interface function
- //if (isOverride())
- //error("is marked as override, but does not override any function");
- cd->vtblFinal.push(this);
- }
- else
- {
- //printf("\tintroducing function %s\n", toChars());
- introducing = 1;
- if (cd->isCPPclass() && target.cpp.reverseOverloads)
- {
- // with dmc, overloaded functions are grouped and in reverse order
- vtblIndex = (int)cd->vtbl.length;
- for (int i = 0; i < (int)cd->vtbl.length; i++)
- {
- if (cd->vtbl[i]->ident == ident && cd->vtbl[i]->parent == parent)
- {
- vtblIndex = (int)i;
- break;
- }
- }
- // shift all existing functions back
- for (int i = (int)cd->vtbl.length; i > vtblIndex; i--)
- {
- FuncDeclaration *fd = cd->vtbl[i-1]->isFuncDeclaration();
- assert(fd);
- fd->vtblIndex++;
- }
- cd->vtbl.insert(vtblIndex, this);
- }
- else
- {
- // Append to end of vtbl[]
- vi = (int)cd->vtbl.length;
- cd->vtbl.push(this);
- vtblIndex = vi;
- }
- }
- break;
-
- case -2:
- // can't determine because of forward references
- errors = true;
- return;
-
- default:
- {
- FuncDeclaration *fdv = cd->baseClass->vtbl[vi]->isFuncDeclaration();
- FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration();
- // This function is covariant with fdv
-
- if (fdc == this)
- {
- doesoverride = true;
- break;
- }
-
- if (fdc->toParent() == parent)
- {
- //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n",
- // vi, this, this->toChars(), this->type->toChars(), this->loc.toChars(),
- // fdc, fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(),
- // fdv, fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars());
-
- // fdc overrides fdv exactly, then this introduces new function.
- if (fdc->type->mod == fdv->type->mod && this->type->mod != fdv->type->mod)
- goto Lintro;
- }
-
- // This function overrides fdv
- if (fdv->isFinalFunc())
- error("cannot override final function %s", fdv->toPrettyChars());
-
- if (!isOverride())
- {
- if (fdv->isFuture())
- {
- ::deprecation(loc, "@__future base class method %s is being overridden by %s; rename the latter",
- fdv->toPrettyChars(), toPrettyChars());
- // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[]
- goto Lintro;
- }
- else
- {
- int vi2 = findVtblIndex(&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length, false);
- if (vi2 < 0)
- // https://issues.dlang.org/show_bug.cgi?id=17349
- ::deprecation(loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute",
- fdv->toPrettyChars(), toPrettyChars());
- else
- ::error(loc, "implicitly overriding base class method %s with %s deprecated; add 'override' attribute",
- fdv->toPrettyChars(), toPrettyChars());
- }
- }
-
- doesoverride = true;
- if (fdc->toParent() == parent)
- {
- // If both are mixins, or both are not, then error.
- // If either is not, the one that is not overrides the other.
- bool thismixin = this->parent->isClassDeclaration() != NULL;
- bool fdcmixin = fdc->parent->isClassDeclaration() != NULL;
- if (thismixin == fdcmixin)
- {
- error("multiple overrides of same function");
- }
- else if (!thismixin) // fdc overrides fdv
- {
- // this doesn't override any function
- break;
- }
- }
- cd->vtbl[vi] = this;
- vtblIndex = vi;
-
- /* Remember which functions this overrides
- */
- foverrides.push(fdv);
-
- /* This works by whenever this function is called,
- * it actually returns tintro, which gets dynamically
- * cast to type. But we know that tintro is a base
- * of type, so we could optimize it by not doing a
- * dynamic cast, but just subtracting the isBaseOf()
- * offset if the value is != null.
- */
-
- if (fdv->tintro)
- tintro = fdv->tintro;
- else if (!type->equals(fdv->type))
- {
- /* Only need to have a tintro if the vptr
- * offsets differ
- */
- int offset;
- if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
- {
- tintro = fdv->type;
- }
- }
- break;
- }
- }
-
- /* Go through all the interface bases.
- * If this function is covariant with any members of those interface
- * functions, set the tintro.
- */
- Linterfaces:
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- vi = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.length);
- switch (vi)
- {
- case -1:
- break;
-
- case -2:
- // can't determine because of forward references
- errors = true;
- return;
-
- default:
- {
- FuncDeclaration *fdv = (FuncDeclaration *)b->sym->vtbl[vi];
- Type *ti = NULL;
-
- /* Remember which functions this overrides
- */
- foverrides.push(fdv);
-
- /* Should we really require 'override' when implementing
- * an interface function?
- */
- //if (!isOverride())
- //warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars());
-
- if (fdv->tintro)
- ti = fdv->tintro;
- else if (!type->equals(fdv->type))
- {
- /* Only need to have a tintro if the vptr
- * offsets differ
- */
- int offset;
- if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
- {
- ti = fdv->type;
- }
- }
- if (ti)
- {
- if (tintro)
- {
- if (!tintro->nextOf()->equals(ti->nextOf()) &&
- !tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) &&
- !ti->nextOf()->isBaseOf(tintro->nextOf(), NULL))
- {
- error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars());
- }
- }
- tintro = ti;
- }
- goto L2;
- }
- }
- }
-
- if (!doesoverride && isOverride() && (type->nextOf() || !may_override))
- {
- BaseClass *bc = NULL;
- Dsymbol *s = NULL;
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- bc = (*cd->baseclasses)[i];
- s = bc->sym->search_correct(ident);
- if (s) break;
- }
-
- if (s)
- error("does not override any function, did you mean to override '%s%s'?",
- bc->sym->isCPPclass() ? "extern (C++) " : "", s->toPrettyChars());
- else
- error("does not override any function");
- }
-
- L2: ;
-
- /* Go through all the interface bases.
- * Disallow overriding any final functions in the interface(s).
- */
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- if (b->sym)
- {
- Dsymbol *s = search_function(b->sym, ident);
- if (s)
- {
- FuncDeclaration *f2 = s->isFuncDeclaration();
- if (f2)
- {
- f2 = f2->overloadExactMatch(type);
- if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_)
- error("cannot override final function %s.%s", b->sym->toChars(), f2->toPrettyChars());
- }
- }
- }
- }
-
- if (isOverride())
- {
- if (storage_class & STCdisable)
- deprecation("overridden functions cannot be annotated @disable");
- if (isDeprecated())
- deprecation("deprecated functions cannot be annotated @disable");
- }
- }
- else if (isOverride() && !parent->isTemplateInstance())
- error("override only applies to class member functions");
-
- // Reflect this->type to f because it could be changed by findVtblIndex
- f = type->toTypeFunction();
-
-Ldone:
- /* Contracts can only appear without a body when they are virtual interface functions
- */
- if (!fbody && !allowsContractWithoutBody(this))
- error("in and out contracts can only appear without a body when they are virtual interface functions or abstract");
-
- /* Do not allow template instances to add virtual functions
- * to a class.
- */
- if (isVirtual())
- {
- TemplateInstance *ti = parent->isTemplateInstance();
- if (ti)
- {
- // Take care of nested templates
- while (1)
- {
- TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
- if (!ti2)
- break;
- ti = ti2;
- }
-
- // If it's a member template
- ClassDeclaration *cd = ti->tempdecl->isClassMember();
- if (cd)
- {
- error("cannot use template to add virtual function to class '%s'", cd->toChars());
- }
- }
- }
-
- if (isMain())
- checkDmain(); // Check main() parameters and return type
-
- /* Purity and safety can be inferred for some functions by examining
- * the function body.
- */
- if (canInferAttributes(this, sc))
- initInferAttributes(this);
-
- Module::dprogress++;
- semanticRun = PASSsemanticdone;
-
- /* Save scope for possible later use (if we need the
- * function internals)
- */
- _scope = sc->copy();
- _scope->setNoFree();
-
- static bool printedMain = false; // semantic might run more than once
- if (global.params.verbose && !printedMain)
- {
- const char *type = isMain() ? "main" : isWinMain() ? "winmain" : isDllMain() ? "dllmain" : (const char *)NULL;
- Module *mod = sc->_module;
-
- if (type && mod)
- {
- printedMain = true;
- const char *name = mod->srcfile->toChars();
- const char *path = FileName::searchPath(global.path, name, true);
- message("entry %-10s\t%s", type, path ? path : name);
- }
- }
-
- if (fbody && isMain() && sc->_module->isRoot())
- Compiler::genCmain(sc);
-
- assert(type->ty != Terror || errors);
-
- // semantic for parameters' UDAs
- const size_t nparams = f->parameterList.length();
- for (size_t i = 0; i < nparams; i++)
- {
- Parameter *param = f->parameterList[i];
- if (param && param->userAttribDecl)
- param->userAttribDecl->semantic(sc);
- }
-}
-
-void FuncDeclaration::semantic2(Scope *sc)
-{
- if (semanticRun >= PASSsemantic2done)
- return;
- assert(semanticRun <= PASSsemantic2);
- semanticRun = PASSsemantic2;
-
- objc()->setSelector(this, sc);
- objc()->validateSelector(this);
-
- if (parent->isClassDeclaration())
- {
- objc()->checkLinkage(this);
- }
- if (!type || type->ty != Tfunction)
- return;
- TypeFunction *f = type->toTypeFunction();
- const size_t nparams = f->parameterList.length();
- // semantic for parameters' UDAs
- for (size_t i = 0; i < nparams; i++)
- {
- Parameter *param = f->parameterList[i];
- if (param && param->userAttribDecl)
- param->userAttribDecl->semantic2(sc);
- }
-}
-
/****************************************************
* Determine whether an 'out' contract is declared inside
* the given function or any of its overrides.
@@ -1326,7 +192,7 @@ void FuncDeclaration::semantic2(Scope *sc)
* true found an 'out' contract
* false didn't find one
*/
-static bool needsFensure(FuncDeclaration *fd)
+bool FuncDeclaration::needsFensure(FuncDeclaration *fd)
{
if (fd->fensures)
return true;
@@ -1358,12 +224,10 @@ static bool canBuildResultVar(FuncDeclaration *fd)
/****************************************************
* Rewrite contracts as statements.
- * Params:
- * fdx = the function to rewrite contracts for
*/
-static void buildEnsureRequire(FuncDeclaration *fdx)
+void FuncDeclaration::buildEnsureRequire()
{
- if (fdx->frequires)
+ if (frequires)
{
/* in { statements1... }
* in { statements2... }
@@ -1371,18 +235,18 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
* becomes:
* in { { statements1... } { statements2... } ... }
*/
- assert(fdx->frequires->length);
- Loc loc = (*fdx->frequires)[0]->loc;
+ assert(frequires->length);
+ Loc loc = (*frequires)[0]->loc;
Statements *s = new Statements;
- for (size_t i = 0; i < fdx->frequires->length; i++)
+ for (size_t i = 0; i < frequires->length; i++)
{
- Statement *r = (*fdx->frequires)[i];
+ Statement *r = (*frequires)[i];
s->push(new ScopeStatement(r->loc, r, r->loc));
}
- fdx->frequire = new CompoundStatement(loc, s);
+ frequire = new CompoundStatement(loc, s);
}
- if (fdx->fensures)
+ if (fensures)
{
/* out(id1) { statements1... }
* out(id2) { statements2... }
@@ -1391,13 +255,13 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
* out(__result) { { ref id1 = __result; { statements1... } }
* { ref id2 = __result; { statements2... } } ... }
*/
- assert(fdx->fensures->length);
- Loc loc = (*fdx->fensures)[0].ensure->loc;
+ assert(fensures->length);
+ Loc loc = (*fensures)[0].ensure->loc;
Statements *s = new Statements;
- for (size_t i = 0; i < fdx->fensures->length; i++)
+ for (size_t i = 0; i < fensures->length; i++)
{
- Ensure r = (*fdx->fensures)[i];
- if (r.id && canBuildResultVar(fdx))
+ Ensure r = (*fensures)[i];
+ if (r.id && canBuildResultVar(this))
{
Loc rloc = r.ensure->loc;
IdentifierExp *resultId = new IdentifierExp(rloc, Id::result);
@@ -1413,25 +277,25 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
s->push(r.ensure);
}
}
- fdx->fensure = new CompoundStatement(loc, s);
+ fensure = new CompoundStatement(loc, s);
}
- if (!fdx->isVirtual())
+ 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 *)fdx->type;
+ TypeFunction *f = (TypeFunction *)type;
- if (fdx->frequire)
+ if (frequire)
{
/* in { ... }
* becomes:
* void __require() { ... }
* __require();
*/
- Loc loc = fdx->frequire->loc;
+ Loc loc = frequire->loc;
TypeFunction *tf = new TypeFunction(ParameterList(), Type::tvoid, LINKd);
tf->isnothrow = f->isnothrow;
tf->isnogc = f->isnogc;
@@ -1439,25 +303,25 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
tf->trust = f->trust;
FuncDeclaration *fd = new FuncDeclaration(loc, loc,
Id::require, STCundefined, tf);
- fd->fbody = fdx->frequire;
+ 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);
- fdx->frequire = new CompoundStatement(loc, s1, s2);
- fdx->fdrequire = fd;
+ frequire = new CompoundStatement(loc, s1, s2);
+ fdrequire = fd;
}
- if (fdx->fensure)
+ if (fensure)
{
/* out (result) { ... }
* becomes:
* void __ensure(ref tret result) { ... }
* __ensure(result);
*/
- Loc loc = fdx->fensure->loc;
+ Loc loc = fensure->loc;
Parameters *fparams = new Parameters();
Parameter *p = NULL;
- if (canBuildResultVar(fdx))
+ if (canBuildResultVar(this))
{
p = new Parameter(STCref | STCconst, f->nextOf(), Id::result, NULL, NULL);
fparams->push(p);
@@ -1469,1051 +333,18 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
tf->trust = f->trust;
FuncDeclaration *fd = new FuncDeclaration(loc, loc,
Id::ensure, STCundefined, tf);
- fd->fbody = fdx->fensure;
+ fd->fbody = fensure;
Statement *s1 = new ExpStatement(loc, fd);
Expression *eresult = NULL;
- if (canBuildResultVar(fdx))
+ 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);
- fdx->fensure = new CompoundStatement(loc, s1, s2);
- fdx->fdensure = fd;
+ fensure = new CompoundStatement(loc, s1, s2);
+ fdensure = fd;
}
}
-/* Determine if function should add `return 0;`
- */
-static bool addReturn0(FuncDeclaration *funcdecl)
-{
- TypeFunction *f = (TypeFunction *)funcdecl->type;
-
- return f->next->ty == Tvoid &&
- (funcdecl->isMain() || (global.params.betterC && funcdecl->isCMain()));
-}
-
-// Do the semantic analysis on the internals of the function.
-
-void FuncDeclaration::semantic3(Scope *sc)
-{
- VarDeclaration *_arguments = NULL;
-
- if (!parent)
- {
- if (global.errors)
- return;
- //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
- assert(0);
- }
- if (errors || isError(parent))
- {
- errors = true;
- return;
- }
- //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", parent->toChars(), toChars(), this, sc, loc.toChars());
- //fflush(stdout);
- //printf("storage class = x%x %x\n", sc->stc, storage_class);
- //{ static int x; if (++x == 2) *(char*)0=0; }
- //printf("\tlinkage = %d\n", sc->linkage);
-
- if (ident == Id::assign && !inuse)
- {
- if (storage_class & STCinference)
- {
- /* Bugzilla 15044: For generated opAssign function, any errors
- * from its body need to be gagged.
- */
- unsigned oldErrors = global.startGagging();
- ++inuse;
- semantic3(sc);
- --inuse;
- if (global.endGagging(oldErrors)) // if errors happened
- {
- // Disable generated opAssign, because some members forbid identity assignment.
- storage_class |= STCdisable;
- fbody = NULL; // remove fbody which contains the error
- semantic3Errors = false;
- }
- return;
- }
- }
-
- //printf(" sc->incontract = %d\n", (sc->flags & SCOPEcontract));
- if (semanticRun >= PASSsemantic3)
- return;
- semanticRun = PASSsemantic3;
- semantic3Errors = false;
-
- if (!type || type->ty != Tfunction)
- return;
- TypeFunction *f = (TypeFunction *)type;
- if (!inferRetType && f->next->ty == Terror)
- return;
-
- if (!fbody && inferRetType && !f->next)
- {
- error("has no function body with return type inference");
- return;
- }
-
- unsigned oldErrors = global.errors;
-
- if (frequires)
- {
- for (size_t i = 0; i < foverrides.length; i++)
- {
- FuncDeclaration *fdv = foverrides[i];
-
- if (fdv->fbody && !fdv->frequires)
- {
- error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars());
- break;
- }
- }
- }
-
- // Remember whether we need to generate an 'out' contract.
- const bool needEnsure = needsFensure(this);
-
- if (fbody || frequires || needEnsure)
- {
- /* Symbol table into which we place parameters and nested functions,
- * solely to diagnose name collisions.
- */
- localsymtab = new DsymbolTable();
-
- // Establish function scope
- ScopeDsymbol *ss = new ScopeDsymbol();
- // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
- for (Scope *scx = sc; ; scx = scx->enclosing)
- {
- if (scx->scopesym)
- {
- ss->parent = scx->scopesym;
- break;
- }
- }
- ss->loc = loc;
- ss->endlinnum = endloc.linnum;
- Scope *sc2 = sc->push(ss);
- sc2->func = this;
- sc2->parent = this;
- sc2->callSuper = 0;
- sc2->sbreak = NULL;
- sc2->scontinue = NULL;
- sc2->sw = NULL;
- sc2->fes = fes;
- sc2->linkage = LINKd;
- sc2->stc &= ~(STCauto | STCscope | STCstatic | STCextern | STCabstract |
- STCdeprecated | STCoverride |
- STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | STCreturn |
- STCproperty | STCnothrow | STCpure | STCsafe | STCtrusted | STCsystem);
- sc2->protection = Prot(Prot::public_);
- sc2->explicitProtection = 0;
- sc2->aligndecl = NULL;
- if (this->ident != Id::require && this->ident != Id::ensure)
- sc2->flags = sc->flags & ~SCOPEcontract;
- sc2->flags &= ~SCOPEcompile;
- sc2->tf = NULL;
- sc2->os = NULL;
- sc2->noctor = 0;
- sc2->userAttribDecl = NULL;
- if (sc2->intypeof == 1) sc2->intypeof = 2;
- sc2->fieldinit = NULL;
- sc2->fieldinit_dim = 0;
-
- /* Note: When a lambda is defined immediately under aggregate member
- * scope, it should be contextless due to prevent interior pointers.
- * e.g.
- * // dg points 'this' - it's interior pointer
- * class C { int x; void delegate() dg = (){ this.x = 1; }; }
- *
- * However, lambdas could be used inside typeof, in order to check
- * some expressions varidity at compile time. For such case the lambda
- * body can access aggregate instance members.
- * e.g.
- * class C { int x; static assert(is(typeof({ this.x = 1; }))); }
- *
- * To properly accept it, mark these lambdas as member functions.
- */
- if (FuncLiteralDeclaration *fld = isFuncLiteralDeclaration())
- {
- if (AggregateDeclaration *ad = isMember2())
- {
- if (!sc->intypeof)
- {
- if (fld->tok == TOKdelegate)
- error("cannot be %s members", ad->kind());
- else
- fld->tok = TOKfunction;
- }
- else
- {
- if (fld->tok != TOKfunction)
- fld->tok = TOKdelegate;
- }
- }
- }
-
- // Declare 'this'
- AggregateDeclaration *ad = isThis();
- vthis = declareThis(sc2, ad);
- //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis);
- //if (vthis) printf("\tvthis->type = %s\n", vthis->type->toChars());
-
- // Declare hidden variable _arguments[] and _argptr
- if (f->parameterList.varargs == VARARGvariadic)
- {
- if (f->linkage == LINKd)
- {
- // Variadic arguments depend on Typeinfo being defined
- if (!global.params.useTypeInfo || !Type::dtypeinfo || !Type::typeinfotypelist)
- {
- if (!global.params.useTypeInfo)
- error("D-style variadic functions cannot be used with -betterC");
- else if (!Type::typeinfotypelist)
- error("`object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions");
- else
- error("`object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions");
- fatal();
- }
-
- // Declare _arguments[]
- v_arguments = new VarDeclaration(Loc(), Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL);
- v_arguments->storage_class |= STCtemp | STCparameter;
- v_arguments->semantic(sc2);
- sc2->insert(v_arguments);
- v_arguments->parent = this;
-
- //Type *t = Type::typeinfo->type->constOf()->arrayOf();
- Type *t = Type::dtypeinfo->type->arrayOf();
- _arguments = new VarDeclaration(Loc(), t, Id::_arguments, NULL);
- _arguments->storage_class |= STCtemp;
- _arguments->semantic(sc2);
- sc2->insert(_arguments);
- _arguments->parent = this;
- }
- if (f->linkage == LINKd || f->parameterList.length())
- {
- // Declare _argptr
- Type *t = target.va_listType(loc, sc);
- v_argptr = new VarDeclaration(Loc(), t, Id::_argptr, NULL);
- v_argptr->storage_class |= STCtemp;
- v_argptr->semantic(sc2);
- sc2->insert(v_argptr);
- v_argptr->parent = this;
- }
- }
-
- /* Declare all the function parameters as variables
- * and install them in parameters[]
- */
- size_t nparams = f->parameterList.length();
- if (nparams)
- {
- /* parameters[] has all the tuples removed, as the back end
- * doesn't know about tuples
- */
- parameters = new VarDeclarations();
- parameters->reserve(nparams);
- for (size_t i = 0; i < nparams; i++)
- {
- Parameter *fparam = f->parameterList[i];
- Identifier *id = fparam->ident;
- StorageClass stc = 0;
- if (!id)
- {
- /* Generate identifier for un-named parameter,
- * because we need it later on.
- */
- fparam->ident = id = Identifier::generateId("_param_", i);
- stc |= STCtemp;
- }
- Type *vtype = fparam->type;
- VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL);
- //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars());
- stc |= STCparameter;
- if (f->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- stc |= STCvariadic;
- if (flags & FUNCFLAGinferScope && !(fparam->storageClass & STCscope))
- stc |= STCmaybescope;
- stc |= fparam->storageClass & (STCin | STCout | STCref | STCreturn | STCscope | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
- v->storage_class = stc;
- v->semantic(sc2);
- if (!sc2->insert(v))
- error("parameter %s.%s is already defined", toChars(), v->toChars());
- else
- parameters->push(v);
- localsymtab->insert(v);
- v->parent = this;
- if (fparam->userAttribDecl)
- v->userAttribDecl = fparam->userAttribDecl;
- }
- }
-
- // Declare the tuple symbols and put them in the symbol table,
- // but not in parameters[].
- if (f->parameterList.parameters)
- {
- for (size_t i = 0; i < f->parameterList.parameters->length; i++)
- {
- Parameter *fparam = (*f->parameterList.parameters)[i];
-
- if (!fparam->ident)
- continue; // never used, so ignore
- if (fparam->type->ty == Ttuple)
- {
- TypeTuple *t = (TypeTuple *)fparam->type;
- size_t dim = Parameter::dim(t->arguments);
- Objects *exps = new Objects();
- exps->setDim(dim);
- for (size_t j = 0; j < dim; j++)
- {
- Parameter *narg = Parameter::getNth(t->arguments, j);
- assert(narg->ident);
- VarDeclaration *v = sc2->search(Loc(), narg->ident, NULL)->isVarDeclaration();
- assert(v);
- Expression *e = new VarExp(v->loc, v);
- (*exps)[j] = e;
- }
- assert(fparam->ident);
- TupleDeclaration *v = new TupleDeclaration(loc, fparam->ident, exps);
- //printf("declaring tuple %s\n", v->toChars());
- v->isexp = true;
- if (!sc2->insert(v))
- error("parameter %s.%s is already defined", toChars(), v->toChars());
- localsymtab->insert(v);
- v->parent = this;
- }
- }
- }
-
- // Precondition invariant
- Statement *fpreinv = NULL;
- if (addPreInvariant())
- {
- Expression *e = addInvariant(ad, vthis);
- if (e)
- fpreinv = new ExpStatement(Loc(), e);
- }
-
- // Postcondition invariant
- Statement *fpostinv = NULL;
- if (addPostInvariant())
- {
- Expression *e = addInvariant(ad, vthis);
- if (e)
- fpostinv = new ExpStatement(Loc(), e);
- }
-
- // Pre/Postcondition contract
- if (!fbody)
- buildEnsureRequire(this);
-
- Scope *scout = NULL;
- if (needEnsure || addPostInvariant())
- {
- if ((needEnsure && global.params.useOut == CHECKENABLEon) || fpostinv)
- {
- returnLabel = new LabelDsymbol(Id::returnLabel);
- }
-
- // scope of out contract (need for vresult->semantic)
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc2->scopesym;
- sym->loc = loc;
- sym->endlinnum = endloc.linnum;
- scout = sc2->push(sym);
- }
-
- if (fbody)
- {
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc2->scopesym;
- sym->loc = loc;
- sym->endlinnum = endloc.linnum;
- sc2 = sc2->push(sym);
-
- AggregateDeclaration *ad2 = isMember2();
-
- /* If this is a class constructor
- */
- if (ad2 && isCtorDeclaration())
- {
- allocFieldinit(sc2, ad2->fields.length);
- for (size_t i = 0; i < ad2->fields.length; i++)
- {
- VarDeclaration *v = ad2->fields[i];
- v->ctorinit = 0;
- }
- }
-
- bool inferRef = (f->isref && (storage_class & STCauto));
-
- fbody = ::semantic(fbody, sc2);
- if (!fbody)
- fbody = new CompoundStatement(Loc(), new Statements());
-
- if (naked)
- {
- fpreinv = NULL; // can't accommodate with no stack frame
- fpostinv = NULL;
- }
-
- assert(type == f ||
- (type->ty == Tfunction &&
- f->purity == PUREimpure &&
- ((TypeFunction *)type)->purity >= PUREfwdref));
- f = (TypeFunction *)type;
-
- if (inferRetType)
- {
- // If no return type inferred yet, then infer a void
- if (!f->next)
- f->next = Type::tvoid;
- if (f->checkRetType(loc))
- fbody = new ErrorStatement();
- }
- if (global.params.vcomplex && f->next != NULL)
- f->next->checkComplexTransition(loc);
-
- if (returns && !fbody->isErrorStatement())
- {
- for (size_t i = 0; i < returns->length; )
- {
- Expression *exp = (*returns)[i]->exp;
- if (exp->op == TOKvar && ((VarExp *)exp)->var == vresult)
- {
- if (addReturn0(this))
- exp->type = Type::tint32;
- else
- exp->type = f->next;
- // Remove `return vresult;` from returns
- returns->remove(i);
- continue;
- }
- if (inferRef && f->isref && !exp->type->constConv(f->next)) // Bugzilla 13336
- f->isref = false;
- i++;
- }
- }
- if (f->isref) // Function returns a reference
- {
- if (storage_class & STCauto)
- storage_class &= ~STCauto;
- }
- if (!target.isReturnOnStack(f, needThis()) || !checkNRVO())
- nrvo_can = 0;
-
- if (fbody->isErrorStatement())
- ;
- else if (isStaticCtorDeclaration())
- {
- /* It's a static constructor. Ensure that all
- * ctor consts were initialized.
- */
- ScopeDsymbol *pd = toParent()->isScopeDsymbol();
- for (size_t i = 0; i < pd->members->length; i++)
- {
- Dsymbol *s = (*pd->members)[i];
- s->checkCtorConstInit();
- }
- }
- else if (ad2 && isCtorDeclaration())
- {
- ClassDeclaration *cd = ad2->isClassDeclaration();
-
- // Verify that all the ctorinit fields got initialized
- if (!(sc2->callSuper & CSXthis_ctor))
- {
- for (size_t i = 0; i < ad2->fields.length; i++)
- {
- VarDeclaration *v = ad2->fields[i];
- if (v->isThisDeclaration())
- continue;
- if (v->ctorinit == 0)
- {
- /* Current bugs in the flow analysis:
- * 1. union members should not produce error messages even if
- * not assigned to
- * 2. structs should recognize delegating opAssign calls as well
- * as delegating calls to other constructors
- */
- if (v->isCtorinit() && !v->type->isMutable() && cd)
- error("missing initializer for %s field %s", MODtoChars(v->type->mod), v->toChars());
- else if (v->storage_class & STCnodefaultctor)
- ::error(loc, "field %s must be initialized in constructor", v->toChars());
- else if (v->type->needsNested())
- ::error(loc, "field %s must be initialized in constructor, because it is nested struct", v->toChars());
- }
- else
- {
- bool mustInit = (v->storage_class & STCnodefaultctor ||
- v->type->needsNested());
- if (mustInit && !(sc2->fieldinit[i] & CSXthis_ctor))
- {
- error("field %s must be initialized but skipped", v->toChars());
- }
- }
- }
- }
- freeFieldinit(sc2);
-
- if (cd &&
- !(sc2->callSuper & CSXany_ctor) &&
- cd->baseClass && cd->baseClass->ctor)
- {
- sc2->callSuper = 0;
-
- // Insert implicit super() at start of fbody
- FuncDeclaration *fd = resolveFuncCall(Loc(), sc2, cd->baseClass->ctor, NULL, vthis->type, NULL, 1);
- if (!fd)
- {
- error("no match for implicit super() call in constructor");
- }
- else if (fd->storage_class & STCdisable)
- {
- error("cannot call super() implicitly because it is annotated with @disable");
- }
- else
- {
- Expression *e1 = new SuperExp(Loc());
- Expression *e = new CallExp(Loc(), e1);
- e = ::semantic(e, sc2);
-
- Statement *s = new ExpStatement(Loc(), e);
- fbody = new CompoundStatement(Loc(), s, fbody);
- }
- }
- //printf("callSuper = x%x\n", sc2->callSuper);
- }
-
- /* https://issues.dlang.org/show_bug.cgi?id=17502
- * Wait until after the return type has been inferred before
- * generating the contracts for this function, and merging contracts
- * from overrides.
- *
- * https://issues.dlang.org/show_bug.cgi?id=17893
- * However should take care to generate this before inferered
- * function attributes are applied, such as 'nothrow'.
- *
- * This was originally at the end of the first semantic pass, but
- * required a fix-up to be done here for the '__result' variable
- * type of __ensure() inside auto functions, but this didn't work
- * if the out parameter was implicit.
- */
- buildEnsureRequire(this);
-
- int blockexit = BEnone;
- if (!fbody->isErrorStatement())
- {
- // Check for errors related to 'nothrow'.
- unsigned int nothrowErrors = global.errors;
- blockexit = blockExit(fbody, this, f->isnothrow);
- if (f->isnothrow && (global.errors != nothrowErrors))
- ::error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars());
- if (flags & FUNCFLAGnothrowInprocess)
- {
- if (type == f) f = (TypeFunction *)f->copy();
- f->isnothrow = !(blockexit & BEthrow);
- }
- }
-
- if (fbody->isErrorStatement())
- ;
- else if (ad2 && isCtorDeclaration())
- {
- /* Append:
- * return this;
- * to function body
- */
- if (blockexit & BEfallthru)
- {
- Statement *s = new ReturnStatement(loc, NULL);
- s = ::semantic(s, sc2);
- fbody = new CompoundStatement(loc, fbody, s);
- hasReturnExp |= (hasReturnExp & 1 ? 16 : 1);
- }
- }
- else if (fes)
- {
- // For foreach(){} body, append a return 0;
- if (blockexit & BEfallthru)
- {
- Expression *e = new IntegerExp(0);
- Statement *s = new ReturnStatement(Loc(), e);
- fbody = new CompoundStatement(Loc(), fbody, s);
- hasReturnExp |= (hasReturnExp & 1 ? 16 : 1);
- }
- assert(!returnLabel);
- }
- else
- {
- const bool inlineAsm = (hasReturnExp & 8) != 0;
- if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
- {
- Expression *e;
- if (!hasReturnExp)
- error("has no return statement, but is expected to return a value of type %s", f->next->toChars());
- else
- error("no return exp; or assert(0); at end of function");
- if (global.params.useAssert == CHECKENABLEon &&
- !global.params.useInline)
- {
- /* Add an assert(0, msg); where the missing return
- * should be.
- */
- e = new AssertExp(
- endloc,
- new IntegerExp(0),
- new StringExp(loc, const_cast<char *>("missing return expression"))
- );
- }
- else
- e = new HaltExp(endloc);
- e = new CommaExp(Loc(), e, f->next->defaultInit());
- e = ::semantic(e, sc2);
- Statement *s = new ExpStatement(Loc(), e);
- fbody = new CompoundStatement(Loc(), fbody, s);
- }
- }
-
- if (returns)
- {
- bool implicit0 = addReturn0(this);
- Type *tret = implicit0 ? Type::tint32 : f->next;
- assert(tret->ty != Tvoid);
- if (vresult || returnLabel)
- buildResultVar(scout ? scout : sc2, tret);
-
- /* Cannot move this loop into NrvoWalker, because
- * returns[i] may be in the nested delegate for foreach-body.
- */
- for (size_t i = 0; i < returns->length; i++)
- {
- ReturnStatement *rs = (*returns)[i];
- Expression *exp = rs->exp;
- if (exp->op == TOKerror)
- continue;
- if (tret->ty == Terror)
- {
- // Bugzilla 13702
- exp = checkGC(sc2, exp);
- continue;
- }
-
- if (!exp->implicitConvTo(tret) &&
- parametersIntersect(exp->type))
- {
- if (exp->type->immutableOf()->implicitConvTo(tret))
- exp = exp->castTo(sc2, exp->type->immutableOf());
- else if (exp->type->wildOf()->implicitConvTo(tret))
- exp = exp->castTo(sc2, exp->type->wildOf());
- }
- exp = exp->implicitCastTo(sc2, tret);
-
- if (f->isref)
- {
- // Function returns a reference
- exp = exp->toLvalue(sc2, exp);
- checkReturnEscapeRef(sc2, exp, false);
- }
- else
- {
- exp = exp->optimize(WANTvalue);
-
- /* Bugzilla 10789:
- * If NRVO is not possible, all returned lvalues should call their postblits.
- */
- if (!nrvo_can)
- exp = doCopyOrMove(sc2, exp);
-
- if (tret->hasPointers())
- checkReturnEscape(sc2, exp, false);
- }
-
- exp = checkGC(sc2, exp);
-
- if (vresult)
- {
- // Create: return vresult = exp;
- exp = new BlitExp(rs->loc, vresult, exp);
- exp->type = vresult->type;
-
- if (rs->caseDim)
- exp = Expression::combine(exp, new IntegerExp(rs->caseDim));
- }
- else if (tintro && !tret->equals(tintro->nextOf()))
- {
- exp = exp->implicitCastTo(sc2, tintro->nextOf());
- }
- rs->exp = exp;
- }
- }
- if (nrvo_var || returnLabel)
- {
- NrvoWalker nw;
- nw.fd = this;
- nw.sc = sc2;
- nw.visitStmt(fbody);
- }
-
- sc2 = sc2->pop();
- }
-
- frequire = mergeFrequire(frequire);
- fensure = mergeFensure(fensure, Id::result);
-
- Statement *freq = frequire;
- Statement *fens = fensure;
-
- /* Do the semantic analysis on the [in] preconditions and
- * [out] postconditions.
- */
- if (freq)
- {
- /* frequire is composed of the [in] contracts
- */
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc2->scopesym;
- sym->loc = loc;
- sym->endlinnum = endloc.linnum;
- sc2 = sc2->push(sym);
- sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPErequire;
-
- // BUG: need to error if accessing out parameters
- // BUG: need to disallow returns and throws
- // BUG: verify that all in and ref parameters are read
- freq = ::semantic(freq, sc2);
- blockExit(freq, this, false);
-
- sc2 = sc2->pop();
-
- if (global.params.useIn == CHECKENABLEoff)
- freq = NULL;
- }
-
- if (fens)
- {
- /* fensure is composed of the [out] contracts
- */
- if (f->next->ty == Tvoid && fensures)
- {
- for (size_t i = 0; i < fensures->length; i++)
- {
- Ensure e = (*fensures)[i];
- if (e.id)
- {
- error(e.ensure->loc, "`void` functions have no result");
- //fens = NULL;
- }
- }
- }
-
- sc2 = scout; //push
- sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPEensure;
-
- // BUG: need to disallow returns and throws
- if (fensure && f->next->ty != Tvoid)
- buildResultVar(scout, f->next);
-
- fens = ::semantic(fens, sc2);
- blockExit(fens, this, false);
-
- sc2 = sc2->pop();
-
- if (global.params.useOut == CHECKENABLEoff)
- fens = NULL;
- }
-
- if (fbody && fbody->isErrorStatement())
- ;
- else
- {
- Statements *a = new Statements();
-
- // Merge in initialization of 'out' parameters
- if (parameters)
- {
- for (size_t i = 0; i < parameters->length; i++)
- {
- VarDeclaration *v = (*parameters)[i];
- if (v->storage_class & STCout)
- {
- assert(v->_init);
- ExpInitializer *ie = v->_init->isExpInitializer();
- assert(ie);
- if (ie->exp->op == TOKconstruct)
- ie->exp->op = TOKassign; // construction occured in parameter processing
- a->push(new ExpStatement(Loc(), ie->exp));
- }
- }
- }
-
- if (v_argptr)
- {
- // Handled in FuncDeclaration::toObjFile
- v_argptr->_init = new VoidInitializer(loc);
- }
-
- if (_arguments)
- {
- /* Advance to elements[] member of TypeInfo_Tuple with:
- * _arguments = v_arguments.elements;
- */
- Expression *e = new VarExp(Loc(), v_arguments);
- e = new DotIdExp(Loc(), e, Id::elements);
- e = new ConstructExp(Loc(), _arguments, e);
- e = ::semantic(e, sc2);
-
- _arguments->_init = new ExpInitializer(Loc(), e);
- DeclarationExp *de = new DeclarationExp(Loc(), _arguments);
- a->push(new ExpStatement(Loc(), de));
- }
-
- // Merge contracts together with body into one compound statement
-
- if (freq || fpreinv)
- {
- if (!freq)
- freq = fpreinv;
- else if (fpreinv)
- freq = new CompoundStatement(Loc(), freq, fpreinv);
-
- a->push(freq);
- }
-
- if (fbody)
- a->push(fbody);
-
- if (fens || fpostinv)
- {
- if (!fens)
- fens = fpostinv;
- else if (fpostinv)
- fens = new CompoundStatement(Loc(), fpostinv, fens);
-
- LabelStatement *ls = new LabelStatement(Loc(), Id::returnLabel, fens);
- returnLabel->statement = ls;
- a->push(returnLabel->statement);
-
- if (f->next->ty != Tvoid && vresult)
- {
- // Create: return vresult;
- Expression *e = new VarExp(Loc(), vresult);
- if (tintro)
- {
- e = e->implicitCastTo(sc, tintro->nextOf());
- e = ::semantic(e, sc);
- }
- ReturnStatement *s = new ReturnStatement(Loc(), e);
- a->push(s);
- }
- }
- if (addReturn0(this))
- {
- // Add a return 0; statement
- Statement *s = new ReturnStatement(Loc(), new IntegerExp(0));
- a->push(s);
- }
-
- Statement *sbody = new CompoundStatement(Loc(), a);
- /* Append destructor calls for parameters as finally blocks.
- */
- if (parameters)
- {
- for (size_t i = 0; i < parameters->length; i++)
- {
- VarDeclaration *v = (*parameters)[i];
-
- if (v->storage_class & (STCref | STCout | STClazy))
- continue;
-
- if (v->needsScopeDtor())
- {
- // same with ExpStatement.scopeCode()
- Statement *s = new DtorExpStatement(Loc(), v->edtor, v);
- v->storage_class |= STCnodtor;
-
- s = ::semantic(s, sc2);
-
- bool isnothrow = f->isnothrow & !(flags & FUNCFLAGnothrowInprocess);
- int blockexit = blockExit(s, this, isnothrow);
- if (f->isnothrow && isnothrow && blockexit & BEthrow)
- ::error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars());
- if (flags & FUNCFLAGnothrowInprocess && blockexit & BEthrow)
- f->isnothrow = false;
- if (blockExit(sbody, this, f->isnothrow) == BEfallthru)
- sbody = new CompoundStatement(Loc(), sbody, s);
- else
- sbody = new TryFinallyStatement(Loc(), sbody, s);
- }
- }
- }
- // from this point on all possible 'throwers' are checked
- flags &= ~FUNCFLAGnothrowInprocess;
-
- if (isSynchronized())
- {
- /* Wrap the entire function body in a synchronized statement
- */
- ClassDeclaration *cd = isThis() ? isThis()->isClassDeclaration() : parent->isClassDeclaration();
-
- if (cd)
- {
- if (!global.params.is64bit &&
- global.params.isWindows &&
- !isStatic() && !sbody->usesEH() && !global.params.trace)
- {
- /* The back end uses the "jmonitor" hack for syncing;
- * no need to do the sync at this level.
- */
- }
- else
- {
- Expression *vsync;
- if (isStatic())
- {
- // The monitor is in the ClassInfo
- vsync = new DotIdExp(loc, resolve(loc, sc2, cd, false), Id::classinfo);
- }
- else
- {
- // 'this' is the monitor
- vsync = new VarExp(loc, vthis);
- }
- sbody = new PeelStatement(sbody); // don't redo semantic()
- sbody = new SynchronizedStatement(loc, vsync, sbody);
- sbody = ::semantic(sbody, sc2);
- }
- }
- else
- {
- error("synchronized function %s must be a member of a class", toChars());
- }
- }
-
- // If declaration has no body, don't set sbody to prevent incorrect codegen.
- if (fbody || allowsContractWithoutBody(this))
- fbody = sbody;
- }
-
- // Fix up forward-referenced gotos
- if (gotos)
- {
- for (size_t i = 0; i < gotos->length; ++i)
- {
- (*gotos)[i]->checkLabel();
- }
- }
-
- if (naked && (fensures || frequires))
- error("naked assembly functions with contracts are not supported");
-
- sc2->callSuper = 0;
- sc2->pop();
- }
-
- if (checkClosure())
- {
- // We should be setting errors here instead of relying on the global error count.
- //errors = true;
- }
-
- /* If function survived being marked as impure, then it is pure
- */
- if (flags & FUNCFLAGpurityInprocess)
- {
- flags &= ~FUNCFLAGpurityInprocess;
- if (type == f)
- f = (TypeFunction *)f->copy();
- f->purity = PUREfwdref;
- }
-
- if (flags & FUNCFLAGsafetyInprocess)
- {
- flags &= ~FUNCFLAGsafetyInprocess;
- if (type == f)
- f = (TypeFunction *)f->copy();
- f->trust = TRUSTsafe;
- }
-
- if (flags & FUNCFLAGnogcInprocess)
- {
- flags &= ~FUNCFLAGnogcInprocess;
- if (type == f)
- f = (TypeFunction *)f->copy();
- f->isnogc = true;
- }
-
- if (flags & FUNCFLAGreturnInprocess)
- {
- flags &= ~FUNCFLAGreturnInprocess;
- if (storage_class & STCreturn)
- {
- if (type == f)
- f = (TypeFunction *)f->copy();
- f->isreturn = true;
- }
- }
-
- flags &= ~FUNCFLAGinferScope;
-
- // Infer STCscope
- if (parameters)
- {
- size_t nfparams = f->parameterList.length();
- assert(nfparams == parameters->length);
- for (size_t u = 0; u < parameters->length; u++)
- {
- VarDeclaration *v = (*parameters)[u];
- if (v->storage_class & STCmaybescope)
- {
- //printf("Inferring scope for %s\n", v->toChars());
- Parameter *p = f->parameterList[u];
- v->storage_class &= ~STCmaybescope;
- v->storage_class |= STCscope | STCscopeinferred;
- p->storageClass |= STCscope | STCscopeinferred;
- assert(!(p->storageClass & STCmaybescope));
- }
- }
- }
-
- if (vthis && vthis->storage_class & STCmaybescope)
- {
- vthis->storage_class &= ~STCmaybescope;
- vthis->storage_class |= STCscope | STCscopeinferred;
- f->isscope = true;
- f->isscopeinferred = true;
- }
-
- // reset deco to apply inference result to mangled name
- if (f != type)
- f->deco = NULL;
-
- // Do semantic type AFTER pure/nothrow inference.
- if (!f->deco && ident != Id::xopEquals && ident != Id::xopCmp)
- {
- sc = sc->push();
- if (isCtorDeclaration()) // Bugzilla #15665
- sc->flags |= SCOPEctor;
- sc->stc = 0;
- sc->linkage = linkage; // Bugzilla 8496
- type = f->semantic(loc, sc);
- sc = sc->pop();
- }
-
- /* If this function had instantiated with gagging, error reproduction will be
- * done by TemplateInstance::semantic.
- * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
- */
- semanticRun = PASSsemantic3done;
- semantic3Errors = (global.errors != oldErrors) || (fbody && fbody->isErrorStatement());
- if (type->ty == Terror)
- errors = true;
- //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars());
- //fflush(stdout);
-}
-
/****************************************************
* Resolve forward reference of function signature -
* parameter types, return type, and attributes.
@@ -2531,7 +362,7 @@ bool FuncDeclaration::functionSemantic()
unsigned oldgag = global.gag;
if (global.gag && !spec)
global.gag = 0;
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
global.gag = oldgag;
if (spec && global.errors != olderrs)
spec->errors = (global.errors - olderrs != 0);
@@ -2586,7 +417,7 @@ bool FuncDeclaration::functionSemantic3()
unsigned oldgag = global.gag;
if (global.gag && !spec)
global.gag = 0;
- semantic3(_scope);
+ semantic3(this, _scope);
global.gag = oldgag;
// If it is a speculatively-instantiated template, and errors occur,
@@ -2615,7 +446,7 @@ bool FuncDeclaration::checkForwardRef(Loc loc)
if (!type->deco)
{
bool inSemantic3 = (inferRetType && semanticRun >= PASSsemantic3);
- ::error(loc, "forward reference to %s'%s'",
+ ::error(loc, "forward reference to %s`%s`",
(inSemantic3 ? "inferred return type of function " : ""),
toChars());
return true;
@@ -2655,7 +486,7 @@ VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad
if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
v->storage_class |= STCmaybescope;
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
if (!sc->insert(v))
assert(0);
v->parent = this;
@@ -2681,7 +512,7 @@ VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad
if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
v->storage_class |= STCmaybescope;
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
if (!sc->insert(v))
assert(0);
v->parent = this;
@@ -2756,7 +587,7 @@ void FuncDeclaration::buildResultVar(Scope *sc, Type *tret)
vresult->storage_class |= STCref;
vresult->type = tret;
- vresult->semantic(sc);
+ dsymbolSemantic(vresult, sc);
if (!sc->insert(vresult))
error("out result %s is already defined", vresult->toChars());
@@ -2816,7 +647,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf)
assert(fdv->_scope);
Scope *sc = fdv->_scope->push();
sc->stc &= ~STCoverride;
- fdv->semantic3(sc);
+ semantic3(fdv, sc);
sc->pop();
}
@@ -2874,7 +705,7 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid)
assert(fdv->_scope);
Scope *sc = fdv->_scope->push();
sc->stc &= ~STCoverride;
- fdv->semantic3(sc);
+ semantic3(fdv, sc);
sc->pop();
}
@@ -3706,7 +1537,7 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
}
else if (od)
{
- ::error(loc, "none of the overloads of '%s' are callable using argument types !(%s)%s",
+ ::error(loc, "none of the overloads of `%s` are callable using argument types !(%s)%s",
od->ident->toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
}
else
@@ -3721,7 +1552,7 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
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:",
+ ::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",
@@ -3731,7 +1562,7 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
{
//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:",
+ ::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 is not callable using argument types %s",
@@ -4296,56 +2127,6 @@ bool FuncDeclaration::addPostInvariant()
!naked);
}
-/********************************************************
- * Generate Expression to call the invariant.
- * Input:
- * ad aggregate with the invariant
- * vthis variable with 'this'
- * Returns:
- * void expression that calls the invariant
- */
-Expression *addInvariant(AggregateDeclaration *ad, VarDeclaration *vthis)
-{
- Expression *e = NULL;
-
- // Call invariant directly only if it exists
- FuncDeclaration *inv = ad->inv;
- ClassDeclaration *cd = ad->isClassDeclaration();
-
- while (!inv && cd)
- {
- cd = cd->baseClass;
- if (!cd)
- break;
- inv = cd->inv;
- }
- if (inv)
- {
- #if 1
- // Workaround for bugzilla 13394: For the correct mangling,
- // run attribute inference on inv if needed.
- inv->functionSemantic();
- #endif
-
- //e = new DsymbolExp(Loc(), inv);
- //e = new CallExp(Loc(), e);
- //e = e->semantic(sc2);
-
- /* https://issues.dlang.org/show_bug.cgi?id=13113
- * Currently virtual invariant calls completely
- * bypass attribute enforcement.
- * Change the behavior of pre-invariant call by following it.
- */
- e = new ThisExp(Loc());
- e->type = vthis->type;
- e = new DotVarExp(Loc(), e, inv, false);
- e->type = inv->type;
- e = new CallExp(Loc(), e);
- e->type = Type::tvoid;
- }
- return e;
-}
-
/**********************************
* Generate a FuncDeclaration for a runtime library function.
*/
@@ -4987,87 +2768,6 @@ Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(f);
}
-void CtorDeclaration::semantic(Scope *sc)
-{
- //printf("CtorDeclaration::semantic() %s\n", toChars());
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = toParent2();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- ::error(loc, "constructor can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not a static constructor
- sc->flags |= SCOPEctor;
-
- FuncDeclaration::semantic(sc);
-
- sc->pop();
-
- if (errors)
- return;
-
- TypeFunction *tf = type->toTypeFunction();
-
- /* See if it's the default constructor
- * But, template constructor should not become a default constructor.
- */
- if (ad && (!parent->isTemplateInstance() || parent->isTemplateMixin()))
- {
- const size_t dim = tf->parameterList.length();
-
- if (StructDeclaration *sd = ad->isStructDeclaration())
- {
- if (dim == 0 && tf->parameterList.varargs == VARARGnone) // empty default ctor w/o any varargs
- {
- if (fbody || !(storage_class & STCdisable) || dim)
- {
- error("default constructor for structs only allowed "
- "with @disable, no body, and no parameters");
- storage_class |= STCdisable;
- fbody = NULL;
- }
- sd->noDefaultCtor = true;
- }
- else if (dim == 0 && tf->parameterList.varargs) // allow varargs only ctor
- {
- }
- else if (dim && tf->parameterList[0]->defaultArg)
- {
- // if the first parameter has a default argument, then the rest does as well
- if (storage_class & STCdisable)
- {
- deprecation("@disable'd constructor cannot have default "
- "arguments for all parameters.");
- deprecationSupplemental(loc, "Use @disable this(); if you want to disable default initialization.");
- }
- else
- deprecation("all parameters have default arguments, "
- "but structs cannot have default constructors.");
- }
-
- }
- else if (dim == 0 && tf->parameterList.varargs == VARARGnone)
- {
- ad->defaultCtor = this;
- }
- }
-}
-
const char *CtorDeclaration::kind() const
{
return "constructor";
@@ -5108,44 +2808,6 @@ Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(dd);
}
-void PostBlitDeclaration::semantic(Scope *sc)
-{
- //printf("PostBlitDeclaration::semantic() %s\n", toChars());
- //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor);
- //printf("stc = x%llx\n", sc->stc);
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = toParent2();
- StructDeclaration *ad = p->isStructDeclaration();
- if (!ad)
- {
- ::error(loc, "postblit can only be a member of struct/union, not %s %s",
- p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
- if (ident == Id::postblit && semanticRun < PASSsemantic)
- ad->postblits.push(this);
- if (!type)
- type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, storage_class);
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not static
- sc->linkage = LINKd;
-
- FuncDeclaration::semantic(sc);
-
- sc->pop();
-}
-
bool PostBlitDeclaration::overloadInsert(Dsymbol *)
{
return false; // cannot overload postblits
@@ -5185,44 +2847,6 @@ Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(dd);
}
-void DtorDeclaration::semantic(Scope *sc)
-{
- //printf("DtorDeclaration::semantic() %s\n", toChars());
- //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor);
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = toParent2();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- ::error(loc, "destructor can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
- if (ident == Id::dtor && semanticRun < PASSsemantic)
- ad->dtors.push(this);
- if (!type)
- type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, storage_class);
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not a static destructor
- if (sc->linkage != LINKcpp)
- sc->linkage = LINKd;
-
- FuncDeclaration::semantic(sc);
-
- sc->pop();
-}
-
bool DtorDeclaration::overloadInsert(Dsymbol *)
{
return false; // cannot overload destructors
@@ -5275,71 +2899,6 @@ Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(scd);
}
-void StaticCtorDeclaration::semantic(Scope *sc)
-{
- //printf("StaticCtorDeclaration::semantic()\n");
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = parent->pastMixin();
- if (!p->isScopeDsymbol())
- {
- const char *s = (isSharedStaticCtorDeclaration() ? "shared " : "");
- ::error(loc, "%sstatic constructor can only be member of module/aggregate/template, not %s %s",
- s, p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
- if (!type)
- type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, storage_class);
-
- /* If the static ctor appears within a template instantiation,
- * it could get called multiple times by the module constructors
- * for different modules. Thus, protect it with a gate.
- */
- if (isInstantiated() && semanticRun < PASSsemantic)
- {
- /* Add this prefix to the function:
- * static int gate;
- * if (++gate != 1) return;
- * Note that this is not thread safe; should not have threads
- * during static construction.
- */
- VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
- v->storage_class = STCtemp | (isSharedStaticCtorDeclaration() ? STCstatic : STCtls);
- Statements *sa = new Statements();
- Statement *s = new ExpStatement(Loc(), v);
- sa->push(s);
- Expression *e = new IdentifierExp(Loc(), v->ident);
- e = new AddAssignExp(Loc(), e, new IntegerExp(1));
- e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(1));
- s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
- sa->push(s);
- if (fbody)
- sa->push(fbody);
- fbody = new CompoundStatement(Loc(), sa);
- }
-
- FuncDeclaration::semantic(sc);
-
- // We're going to need ModuleInfo
- Module *m = getModule();
- if (!m)
- m = sc->_module;
- if (m)
- {
- m->needmoduleinfo = 1;
- //printf("module1 %s needs moduleinfo\n", m->toChars());
- }
-}
-
AggregateDeclaration *StaticCtorDeclaration::isThis()
{
return NULL;
@@ -5402,72 +2961,6 @@ Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(sdd);
}
-void StaticDtorDeclaration::semantic(Scope *sc)
-{
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = parent->pastMixin();
- if (!p->isScopeDsymbol())
- {
- const char *s = (isSharedStaticDtorDeclaration() ? "shared " : "");
- ::error(loc, "%sstatic destructor can only be member of module/aggregate/template, not %s %s",
- s, p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
- if (!type)
- type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, storage_class);
-
- /* If the static ctor appears within a template instantiation,
- * it could get called multiple times by the module constructors
- * for different modules. Thus, protect it with a gate.
- */
- if (isInstantiated() && semanticRun < PASSsemantic)
- {
- /* Add this prefix to the function:
- * static int gate;
- * if (--gate != 0) return;
- * Increment gate during constructor execution.
- * Note that this is not thread safe; should not have threads
- * during static destruction.
- */
- VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
- v->storage_class = STCtemp | (isSharedStaticDtorDeclaration() ? STCstatic : STCtls);
- Statements *sa = new Statements();
- Statement *s = new ExpStatement(Loc(), v);
- sa->push(s);
- Expression *e = new IdentifierExp(Loc(), v->ident);
- e = new AddAssignExp(Loc(), e, new IntegerExp(-1));
- e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(0));
- s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
- sa->push(s);
- if (fbody)
- sa->push(fbody);
- fbody = new CompoundStatement(Loc(), sa);
- vgate = v;
- }
-
- FuncDeclaration::semantic(sc);
-
- // We're going to need ModuleInfo
- Module *m = getModule();
- if (!m)
- m = sc->_module;
- if (m)
- {
- m->needmoduleinfo = 1;
- //printf("module2 %s needs moduleinfo\n", m->toChars());
- }
-}
-
AggregateDeclaration *StaticDtorDeclaration::isThis()
{
return NULL;
@@ -5523,46 +3016,6 @@ Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(id);
}
-void InvariantDeclaration::semantic(Scope *sc)
-{
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = parent->pastMixin();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- ::error(loc, "invariant can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
- if (ident != Id::classInvariant &&
- semanticRun < PASSsemantic &&
- !ad->isUnionDeclaration() // users are on their own with union fields
- )
- ad->invs.push(this);
- if (!type)
- type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, storage_class);
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not a static invariant
- sc->stc |= STCconst; // invariant() is always const
- sc->flags = (sc->flags & ~SCOPEcontract) | SCOPEinvariant;
- sc->linkage = LINKd;
-
- FuncDeclaration::semantic(sc);
-
- sc->pop();
-}
-
bool InvariantDeclaration::isVirtual()
{
return false;
@@ -5605,40 +3058,6 @@ Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(utd);
}
-void UnitTestDeclaration::semantic(Scope *sc)
-{
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- protection = sc->protection;
-
- parent = sc->parent;
- Dsymbol *p = parent->pastMixin();
- if (!p->isScopeDsymbol())
- {
- ::error(loc, "unittest can only be a member of module/aggregate/template, not %s %s",
- p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
-
- if (global.params.useUnitTests)
- {
- if (!type)
- type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, storage_class);
- Scope *sc2 = sc->push();
- sc2->linkage = LINKd;
- FuncDeclaration::semantic(sc2);
- sc2->pop();
- }
-}
-
AggregateDeclaration *UnitTestDeclaration::isThis()
{
return NULL;
@@ -5676,49 +3095,6 @@ Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(f);
}
-void NewDeclaration::semantic(Scope *sc)
-{
- //printf("NewDeclaration::semantic()\n");
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = parent->pastMixin();
- if (!p->isAggregateDeclaration())
- {
- ::error(loc, "allocator can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
- Type *tret = Type::tvoid->pointerTo();
- if (!type)
- type = new TypeFunction(ParameterList(parameters, varargs), tret, LINKd, storage_class);
-
- type = type->semantic(loc, sc);
-
- // Check that there is at least one argument of type size_t
- TypeFunction *tf = type->toTypeFunction();
- if (tf->parameterList.length() < 1)
- {
- error("at least one argument of type size_t expected");
- }
- else
- {
- Parameter *fparam = tf->parameterList[0];
- if (!fparam->type->equals(Type::tsize_t))
- error("first argument must be type size_t, not %s", fparam->type->toChars());
- }
-
- FuncDeclaration::semantic(sc);
-}
-
const char *NewDeclaration::kind() const
{
return "allocator";
@@ -5755,48 +3131,6 @@ Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s)
return FuncDeclaration::syntaxCopy(f);
}
-void DeleteDeclaration::semantic(Scope *sc)
-{
- //printf("DeleteDeclaration::semantic()\n");
- if (semanticRun >= PASSsemanticdone)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- parent = sc->parent;
- Dsymbol *p = parent->pastMixin();
- if (!p->isAggregateDeclaration())
- {
- ::error(loc, "deallocator can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- type = Type::terror;
- errors = true;
- return;
- }
- if (!type)
- type = new TypeFunction(ParameterList(parameters), Type::tvoid, LINKd, storage_class);
-
- type = type->semantic(loc, sc);
-
- // Check that there is only one argument of type void*
- TypeFunction *tf = type->toTypeFunction();
- if (tf->parameterList.length() != 1)
- {
- error("one argument of type void* expected");
- }
- else
- {
- Parameter *fparam = tf->parameterList[0];
- if (!fparam->type->equals(Type::tvoid->pointerTo()))
- error("one argument of type void* expected, not %s", fparam->type->toChars());
- }
-
- FuncDeclaration::semantic(sc);
-}
-
const char *DeleteDeclaration::kind() const
{
return "deallocator";