blob: 7a44ed2c41d859d64192431e6929d5be83001682 [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
*/
#include "root/dsystem.h"
#include "root/aav.h"
#include "dsymbol.h"
#include "aggregate.h"
#include "aliasthis.h"
#include "attrib.h"
#include "cond.h"
#include "declaration.h"
#include "enum.h"
#include "errors.h"
#include "hdrgen.h"
#include "id.h"
#include "import.h"
#include "init.h"
#include "mars.h"
#include "module.h"
#include "nspace.h"
#include "objc.h"
#include "parse.h"
#include "scope.h"
#include "statement.h"
#include "staticassert.h"
#include "target.h"
#include "template.h"
#include "utf.h"
#include "version.h"
#include "visitor.h"
bool allowsContractWithoutBody(FuncDeclaration *funcdecl);
bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0);
VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Initializer *inferType(Initializer *init, Scope *sc);
void MODtoBuffer(OutBuffer *buf, MOD mod);
bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
bool symbolIsVisible(Scope *sc, Dsymbol *s);
Objc *objc();
static unsigned setMangleOverride(Dsymbol *s, char *sym)
{
AttribDeclaration *ad = s->isAttribDeclaration();
if (ad)
{
Dsymbols *decls = ad->include(NULL);
unsigned nestedCount = 0;
if (decls && decls->length)
for (size_t i = 0; i < decls->length; ++i)
nestedCount += setMangleOverride((*decls)[i], sym);
return nestedCount;
}
else if (s->isFuncDeclaration() || s->isVarDeclaration())
{
s->isDeclaration()->mangleOverride = sym;
return 1;
}
else
return 0;
}
/**********************************
* Decide if attributes for this function can be inferred from examining
* the function body.
* Returns:
* true if can
*/
static bool canInferAttributes(FuncDeclaration *fd, Scope *sc)
{
if (!fd->fbody)
return false;
if (fd->isVirtualMethod())
return false; // since they may be overridden
if (sc->func &&
/********** this is for backwards compatibility for the moment ********/
(!fd->isMember() || (sc->func->isSafeBypassingInference() && !fd->isInstantiated())))
return true;
if (fd->isFuncLiteralDeclaration() || // externs are not possible with literals
(fd->storage_class & STCinference) || // do attribute inference
(fd->inferRetType && !fd->isCtorDeclaration()))
return true;
if (fd->isInstantiated())
{
TemplateInstance *ti = fd->parent->isTemplateInstance();
if (ti == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == fd->ident)
return true;
}
return false;
}
/*****************************************
* Initialize for inferring the attributes of this function.
*/
static void initInferAttributes(FuncDeclaration *fd)
{
//printf("initInferAttributes() for %s\n", toPrettyChars());
TypeFunction *tf = fd->type->toTypeFunction();
if (tf->purity == PUREimpure) // purity not specified
fd->flags |= FUNCFLAGpurityInprocess;
if (tf->trust == TRUSTdefault)
fd->flags |= FUNCFLAGsafetyInprocess;
if (!tf->isnothrow)
fd->flags |= FUNCFLAGnothrowInprocess;
if (!tf->isnogc)
fd->flags |= FUNCFLAGnogcInprocess;
if (!fd->isVirtual() || fd->introducing)
fd->flags |= FUNCFLAGreturnInprocess;
// Initialize for inferring STCscope
if (global.params.vsafe)
fd->flags |= FUNCFLAGinferScope;
}
static void badObjectDotD(ClassDeclaration *cd)
{
cd->error("missing or corrupt object.d");
fatal();
}
/* Bugzilla 12078, 12143 and 15733:
* While resolving base classes and interfaces, a base may refer
* the member of this derived class. In that time, if all bases of
* this class can be determined, we can go forward the semantc process
* beyond the Lancestorsdone. To do the recursive semantic analysis,
* temporarily set and unset `_scope` around exp().
*/
static Type *resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, Type *type)
{
if (!scx)
{
scx = sc->copy();
scx->setNoFree();
}
cd->_scope = scx;
Type *t = typeSemantic(type, cd->loc, sc);
cd->_scope = NULL;
return t;
}
static void resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, ClassDeclaration *sym)
{
if (!scx)
{
scx = sc->copy();
scx->setNoFree();
}
cd->_scope = scx;
dsymbolSemantic(sym, NULL);
cd->_scope = NULL;
}
class DsymbolSemanticVisitor : public Visitor
{
public:
Scope *sc;
DsymbolSemanticVisitor(Scope *sc)
{
this->sc = sc;
}
void visit(Dsymbol *dsym)
{
dsym->error("%p has no semantic routine", dsym);
}
void visit(ScopeDsymbol *) { }
void visit(Declaration *) { }
void visit(AliasThis *dsym)
{
if (dsym->semanticRun != PASSinit)
return;
if (dsym->_scope)
{
sc = dsym->_scope;
dsym->_scope = NULL;
}
if (!sc)
return;
dsym->semanticRun = PASSsemantic;
Dsymbol *p = sc->parent->pastMixin();
AggregateDeclaration *ad = p->isAggregateDeclaration();
if (!ad)
{
error(dsym->loc, "alias this can only be a member of aggregate, not %s %s",
p->kind(), p->toChars());
return;
}
assert(ad->members);
Dsymbol *s = ad->search(dsym->loc, dsym->ident);
if (!s)
{
s = sc->search(dsym->loc, dsym->ident, NULL);
if (s)
error(dsym->loc, "%s is not a member of %s", s->toChars(), ad->toChars());
else
error(dsym->loc, "undefined identifier %s", dsym->ident->toChars());
return;
}
else if (ad->aliasthis && s != ad->aliasthis)
{
error(dsym->loc, "there can be only one alias this");
return;
}
if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad)
{
AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym;
assert(ad2->type == Type::terror);
ad->aliasthis = ad2->aliasthis;
return;
}
/* disable the alias this conversion so the implicit conversion check
* doesn't use it.
*/
ad->aliasthis = NULL;
Dsymbol *sx = s;
if (sx->isAliasDeclaration())
sx = sx->toAlias();
Declaration *d = sx->isDeclaration();
if (d && !d->isTupleDeclaration())
{
Type *t = d->type;
assert(t);
if (ad->type->implicitConvTo(t) > MATCHnomatch)
{
error(dsym->loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars());
}
}
ad->aliasthis = s;
dsym->semanticRun = PASSsemanticdone;
}
void visit(AliasDeclaration *dsym)
{
if (dsym->semanticRun >= PASSsemanticdone)
return;
assert(dsym->semanticRun <= PASSsemantic);
dsym->storage_class |= sc->stc & STCdeprecated;
dsym->protection = sc->protection;
dsym->userAttribDecl = sc->userAttribDecl;
if (!sc->func && dsym->inNonRoot())
return;
aliasSemantic(dsym, sc);
}
void visit(VarDeclaration *dsym)
{
//if (dsym->semanticRun > PASSinit)
// return;
//dsym->semanticRun = PASSsemantic;
if (dsym->semanticRun >= PASSsemanticdone)
return;
Scope *scx = NULL;
if (dsym->_scope)
{
sc = dsym->_scope;
scx = sc;
dsym->_scope = NULL;
}
if (!sc)
return;
dsym->semanticRun = PASSsemantic;
/* Pick up storage classes from context, but except synchronized,
* override, abstract, and final.
*/
dsym->storage_class |= (sc->stc & ~(STCsynchronized | STCoverride | STCabstract | STCfinal));
if (dsym->storage_class & STCextern && dsym->_init)
dsym->error("extern symbols cannot have initializers");
dsym->userAttribDecl = sc->userAttribDecl;
AggregateDeclaration *ad = dsym->isThis();
if (ad)
dsym->storage_class |= ad->storage_class & STC_TYPECTOR;
/* If auto type inference, do the inference
*/
int inferred = 0;
if (!dsym->type)
{
dsym->inuse++;
// Infering the type requires running semantic,
// so mark the scope as ctfe if required
bool needctfe = (dsym->storage_class & (STCmanifest | STCstatic)) != 0;
if (needctfe) sc = sc->startCTFE();
//printf("inferring type for %s with init %s\n", dsym->toChars(), dsym->_init->toChars());
dsym->_init = inferType(dsym->_init, sc);
dsym->type = initializerToExpression(dsym->_init)->type;
if (needctfe) sc = sc->endCTFE();
dsym->inuse--;
inferred = 1;
/* This is a kludge to support the existing syntax for RAII
* declarations.
*/
dsym->storage_class &= ~STCauto;
dsym->originalType = dsym->type->syntaxCopy();
}
else
{
if (!dsym->originalType)
dsym->originalType = dsym->type->syntaxCopy();
/* Prefix function attributes of variable declaration can affect
* its type:
* pure nothrow void function() fp;
* static assert(is(typeof(fp) == void function() pure nothrow));
*/
Scope *sc2 = sc->push();
sc2->stc |= (dsym->storage_class & STC_FUNCATTR);
dsym->inuse++;
dsym->type = typeSemantic(dsym->type, dsym->loc, sc2);
dsym->inuse--;
sc2->pop();
}
//printf(" semantic type = %s\n", dsym->type ? dsym->type->toChars() : "null");
if (dsym->type->ty == Terror)
dsym->errors = true;
dsym->type->checkDeprecated(dsym->loc, sc);
dsym->linkage = sc->linkage;
dsym->parent = sc->parent;
//printf("this = %p, parent = %p, '%s'\n", dsym, dsym->parent, dsym->parent->toChars());
dsym->protection = sc->protection;
/* If scope's alignment is the default, use the type's alignment,
* otherwise the scope overrrides.
*/
dsym->alignment = sc->alignment();
if (dsym->alignment == STRUCTALIGN_DEFAULT)
dsym->alignment = dsym->type->alignment(); // use type's alignment
//printf("sc->stc = %x\n", sc->stc);
//printf("storage_class = x%x\n", dsym->storage_class);
if (global.params.vcomplex)
dsym->type->checkComplexTransition(dsym->loc);
// Calculate type size + safety checks
if (sc->func && !sc->intypeof)
{
if ((dsym->storage_class & STCgshared) && !dsym->isMember())
{
if (sc->func->setUnsafe())
dsym->error("__gshared not allowed in safe functions; use shared");
}
}
Dsymbol *parent = dsym->toParent();
Type *tb = dsym->type->toBasetype();
Type *tbn = tb->baseElemOf();
if (tb->ty == Tvoid && !(dsym->storage_class & STClazy))
{
if (inferred)
{
dsym->error("type %s is inferred from initializer %s, and variables cannot be of type void",
dsym->type->toChars(), dsym->_init->toChars());
}
else
dsym->error("variables cannot be of type void");
dsym->type = Type::terror;
tb = dsym->type;
}
if (tb->ty == Tfunction)
{
dsym->error("cannot be declared to be a function");
dsym->type = Type::terror;
tb = dsym->type;
}
if (tb->ty == Tstruct)
{
TypeStruct *ts = (TypeStruct *)tb;
if (!ts->sym->members)
{
dsym->error("no definition of struct `%s`", ts->toChars());
// Explain why the definition is required when it's part of another type
if (!dsym->type->isTypeStruct())
{
// Prefer Loc of the dependant type
Dsymbol *s = dsym->type->toDsymbol(sc);
Loc loc = s ? s->loc : dsym->loc;
errorSupplemental(loc, "required by type `%s`", dsym->type->toChars());
}
// Flag variable as error to avoid invalid error messages due to unknown size
dsym->type = Type::terror;
}
}
if ((dsym->storage_class & STCauto) && !inferred)
dsym->error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?");
if (tb->ty == Ttuple)
{
/* Instead, declare variables for each of the tuple elements
* and add those.
*/
TypeTuple *tt = (TypeTuple *)tb;
size_t nelems = Parameter::dim(tt->arguments);
Expression *ie = (dsym->_init && !dsym->_init->isVoidInitializer()) ? initializerToExpression(dsym->_init) : NULL;
if (ie)
ie = expressionSemantic(ie, sc);
if (nelems > 0 && ie)
{
Expressions *iexps = new Expressions();
iexps->push(ie);
Expressions *exps = new Expressions();
for (size_t pos = 0; pos < iexps->length; pos++)
{
Lexpand1:
Expression *e = (*iexps)[pos];
Parameter *arg = Parameter::getNth(tt->arguments, pos);
arg->type = typeSemantic(arg->type, dsym->loc, sc);
//printf("[%d] iexps->length = %d, ", pos, iexps->length);
//printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
//printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
if (e != ie)
{
if (iexps->length > nelems)
goto Lnomatch;
if (e->type->implicitConvTo(arg->type))
continue;
}
if (e->op == TOKtuple)
{
TupleExp *te = (TupleExp *)e;
if (iexps->length - 1 + te->exps->length > nelems)
goto Lnomatch;
iexps->remove(pos);
iexps->insert(pos, te->exps);
(*iexps)[pos] = Expression::combine(te->e0, (*iexps)[pos]);
goto Lexpand1;
}
else if (isAliasThisTuple(e))
{
VarDeclaration *v = copyToTemp(0, "__tup", e);
dsymbolSemantic(v, sc);
VarExp *ve = new VarExp(dsym->loc, v);
ve->type = e->type;
exps->setDim(1);
(*exps)[0] = ve;
expandAliasThisTuples(exps, 0);
for (size_t u = 0; u < exps->length ; u++)
{
Lexpand2:
Expression *ee = (*exps)[u];
arg = Parameter::getNth(tt->arguments, pos + u);
arg->type = typeSemantic(arg->type, dsym->loc, sc);
//printf("[%d+%d] exps->length = %d, ", pos, u, exps->length);
//printf("ee = (%s %s, %s), ", Token::tochars[ee->op], ee->toChars(), ee->type->toChars());
//printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
size_t iexps_dim = iexps->length - 1 + exps->length;
if (iexps_dim > nelems)
goto Lnomatch;
if (ee->type->implicitConvTo(arg->type))
continue;
if (expandAliasThisTuples(exps, u) != -1)
goto Lexpand2;
}
if ((*exps)[0] != ve)
{
Expression *e0 = (*exps)[0];
(*exps)[0] = new CommaExp(dsym->loc, new DeclarationExp(dsym->loc, v), e0);
(*exps)[0]->type = e0->type;
iexps->remove(pos);
iexps->insert(pos, exps);
goto Lexpand1;
}
}
}
if (iexps->length < nelems)
goto Lnomatch;
ie = new TupleExp(dsym->_init->loc, iexps);
}
Lnomatch:
if (ie && ie->op == TOKtuple)
{
TupleExp *te = (TupleExp *)ie;
size_t tedim = te->exps->length;
if (tedim != nelems)
{
error(dsym->loc, "tuple of %d elements cannot be assigned to tuple of %d elements", (int)tedim, (int)nelems);
for (size_t u = tedim; u < nelems; u++) // fill dummy expression
te->exps->push(new ErrorExp());
}
}
Objects *exps = new Objects();
exps->setDim(nelems);
for (size_t i = 0; i < nelems; i++)
{
Parameter *arg = Parameter::getNth(tt->arguments, i);
OutBuffer buf;
buf.printf("__%s_field_%llu", dsym->ident->toChars(), (ulonglong)i);
const char *name = buf.extractChars();
Identifier *id = Identifier::idPool(name);
Initializer *ti;
if (ie)
{
Expression *einit = ie;
if (ie->op == TOKtuple)
{
TupleExp *te = (TupleExp *)ie;
einit = (*te->exps)[i];
if (i == 0)
einit = Expression::combine(te->e0, einit);
}
ti = new ExpInitializer(einit->loc, einit);
}
else
ti = dsym->_init ? dsym->_init->syntaxCopy() : NULL;
VarDeclaration *v = new VarDeclaration(dsym->loc, arg->type, id, ti);
v->storage_class |= STCtemp | STClocal | dsym->storage_class;
if (arg->storageClass & STCparameter)
v->storage_class |= arg->storageClass;
//printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
dsymbolSemantic(v, sc);
if (sc->scopesym)
{
//printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars());
if (sc->scopesym->members)
sc->scopesym->members->push(v);
}
Expression *e = new DsymbolExp(dsym->loc, v);
(*exps)[i] = e;
}
TupleDeclaration *v2 = new TupleDeclaration(dsym->loc, dsym->ident, exps);
v2->parent = dsym->parent;
v2->isexp = true;
dsym->aliassym = v2;
dsym->semanticRun = PASSsemanticdone;
return;
}
/* Storage class can modify the type
*/
dsym->type = dsym->type->addStorageClass(dsym->storage_class);
/* Adjust storage class to reflect type
*/
if (dsym->type->isConst())
{
dsym->storage_class |= STCconst;
if (dsym->type->isShared())
dsym->storage_class |= STCshared;
}
else if (dsym->type->isImmutable())
dsym->storage_class |= STCimmutable;
else if (dsym->type->isShared())
dsym->storage_class |= STCshared;
else if (dsym->type->isWild())
dsym->storage_class |= STCwild;
if (StorageClass stc = dsym->storage_class & (STCsynchronized | STCoverride | STCabstract | STCfinal))
{
if (stc == STCfinal)
dsym->error("cannot be final, perhaps you meant const?");
else
{
OutBuffer buf;
stcToBuffer(&buf, stc);
dsym->error("cannot be %s", buf.peekChars());
}
dsym->storage_class &= ~stc; // strip off
}
if (dsym->storage_class & STCscope)
{
StorageClass stc = dsym->storage_class & (STCstatic | STCextern | STCmanifest | STCtls | STCgshared);
if (stc)
{
OutBuffer buf;
stcToBuffer(&buf, stc);
dsym->error("cannot be `scope` and `%s`", buf.peekChars());
}
else if (dsym->isMember())
{
dsym->error("field cannot be `scope`");
}
else if (!dsym->type->hasPointers())
{
dsym->storage_class &= ~STCscope; // silently ignore; may occur in generic code
}
}
if (dsym->storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe))
{
}
else
{
AggregateDeclaration *aad = parent->isAggregateDeclaration();
if (aad)
{
if (global.params.vfield &&
dsym->storage_class & (STCconst | STCimmutable) && dsym->_init && !dsym->_init->isVoidInitializer())
{
const char *s = (dsym->storage_class & STCimmutable) ? "immutable" : "const";
message(dsym->loc, "`%s.%s` is `%s` field", ad->toPrettyChars(), dsym->toChars(), s);
}
dsym->storage_class |= STCfield;
if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor)
{
if (!dsym->isThisDeclaration() && !dsym->_init)
aad->noDefaultCtor = true;
}
}
InterfaceDeclaration *id = parent->isInterfaceDeclaration();
if (id)
{
dsym->error("field not allowed in interface");
}
else if (aad && aad->sizeok == SIZEOKdone)
{
dsym->error("cannot be further field because it will change the determined %s size", aad->toChars());
}
/* Templates cannot add fields to aggregates
*/
TemplateInstance *ti = parent->isTemplateInstance();
if (ti)
{
// Take care of nested templates
while (1)
{
TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
if (!ti2)
break;
ti = ti2;
}
// If it's a member template
AggregateDeclaration *ad2 = ti->tempdecl->isMember();
if (ad2 && dsym->storage_class != STCundefined)
{
dsym->error("cannot use template to add field to aggregate `%s`", ad2->toChars());
}
}
}
if ((dsym->storage_class & (STCref | STCparameter | STCforeach | STCtemp | STCresult)) == STCref && dsym->ident != Id::This)
{
dsym->error("only parameters or foreach declarations can be ref");
}
if (dsym->type->hasWild())
{
if (dsym->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) ||
dsym->isDataseg()
)
{
dsym->error("only parameters or stack based variables can be inout");
}
FuncDeclaration *func = sc->func;
if (func)
{
if (func->fes)
func = func->fes->func;
bool isWild = false;
for (FuncDeclaration *fd = func; fd; fd = fd->toParent2()->isFuncDeclaration())
{
if (((TypeFunction *)fd->type)->iswild)
{
isWild = true;
break;
}
}
if (!isWild)
{
dsym->error("inout variables can only be declared inside inout functions");
}
}
}
if (!(dsym->storage_class & (STCctfe | STCref | STCresult)) && tbn->ty == Tstruct &&
((TypeStruct *)tbn)->sym->noDefaultCtor)
{
if (!dsym->_init)
{
if (dsym->isField())
{
/* For fields, we'll check the constructor later to make sure it is initialized
*/
dsym->storage_class |= STCnodefaultctor;
}
else if (dsym->storage_class & STCparameter)
;
else
dsym->error("default construction is disabled for type %s", dsym->type->toChars());
}
}
FuncDeclaration *fd = parent->isFuncDeclaration();
if (dsym->type->isscope() && !(dsym->storage_class & STCnodtor))
{
if (dsym->storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd)
{
dsym->error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope");
}
if (!(dsym->storage_class & STCscope))
{
if (!(dsym->storage_class & STCparameter) && dsym->ident != Id::withSym)
dsym->error("reference to scope class must be scope");
}
}
// Calculate type size + safety checks
if (sc->func && !sc->intypeof)
{
if (dsym->_init && dsym->_init->isVoidInitializer() && dsym->type->hasPointers()) // get type size
{
if (sc->func->setUnsafe())
dsym->error("void initializers for pointers not allowed in safe functions");
}
else if (!dsym->_init &&
!(dsym->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield | STCparameter)) &&
dsym->type->hasVoidInitPointers())
{
if (sc->func->setUnsafe())
dsym->error("void initializers for pointers not allowed in safe functions");
}
}
if (!dsym->_init && !fd)
{
// If not mutable, initializable by constructor only
dsym->storage_class |= STCctorinit;
}
if (dsym->_init)
dsym->storage_class |= STCinit; // remember we had an explicit initializer
else if (dsym->storage_class & STCmanifest)
dsym->error("manifest constants must have initializers");
bool isBlit = false;
d_uns64 sz = 0;
if (!dsym->_init && !sc->inunion && !(dsym->storage_class & (STCstatic | STCgshared | STCextern)) && fd &&
(!(dsym->storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult))
|| (dsym->storage_class & STCout)) &&
(sz = dsym->type->size()) != 0)
{
// Provide a default initializer
//printf("Providing default initializer for '%s'\n", dsym->toChars());
if (sz == SIZE_INVALID && dsym->type->ty != Terror)
dsym->error("size of type %s is invalid", dsym->type->toChars());
Type *tv = dsym->type;
while (tv->ty == Tsarray) // Don't skip Tenum
tv = tv->nextOf();
if (tv->needsNested())
{
/* Nested struct requires valid enclosing frame pointer.
* In StructLiteralExp::toElem(), it's calculated.
*/
assert(tv->toBasetype()->ty == Tstruct);
checkFrameAccess(dsym->loc, sc, ((TypeStruct *)tbn)->sym);
Expression *e = tv->defaultInitLiteral(dsym->loc);
e = new BlitExp(dsym->loc, new VarExp(dsym->loc, dsym), e);
e = expressionSemantic(e, sc);
dsym->_init = new ExpInitializer(dsym->loc, e);
goto Ldtor;
}
if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->zeroInit == 1)
{
/* If a struct is all zeros, as a special case
* set it's initializer to the integer 0.
* In AssignExp::toElem(), we check for this and issue
* a memset() to initialize the struct.
* Must do same check in interpreter.
*/
Expression *e = new IntegerExp(dsym->loc, 0, Type::tint32);
e = new BlitExp(dsym->loc, new VarExp(dsym->loc, dsym), e);
e->type = dsym->type; // don't type check this, it would fail
dsym->_init = new ExpInitializer(dsym->loc, e);
goto Ldtor;
}
if (dsym->type->baseElemOf()->ty == Tvoid)
{
dsym->error("%s does not have a default initializer", dsym->type->toChars());
}
else if (Expression *e = dsym->type->defaultInit(dsym->loc))
{
dsym->_init = new ExpInitializer(dsym->loc, e);
}
// Default initializer is always a blit
isBlit = true;
}
if (dsym->_init)
{
sc = sc->push();
sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCnogc | STCref | STCdisable);
ExpInitializer *ei = dsym->_init->isExpInitializer();
if (ei) // Bugzilla 13424: Preset the required type to fail in FuncLiteralDeclaration::semantic3
ei->exp = inferType(ei->exp, dsym->type);
// If inside function, there is no semantic3() call
if (sc->func || sc->intypeof == 1)
{
// If local variable, use AssignExp to handle all the various
// possibilities.
if (fd &&
!(dsym->storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) &&
!dsym->_init->isVoidInitializer())
{
//printf("fd = '%s', var = '%s'\n", fd->toChars(), dsym->toChars());
if (!ei)
{
ArrayInitializer *ai = dsym->_init->isArrayInitializer();
Expression *e;
if (ai && tb->ty == Taarray)
e = ai->toAssocArrayLiteral();
else
e = initializerToExpression(dsym->_init);
if (!e)
{
// Run semantic, but don't need to interpret
dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, INITnointerpret);
e = initializerToExpression(dsym->_init);
if (!e)
{
dsym->error("is not a static and cannot have static initializer");
e = new ErrorExp();
}
}
ei = new ExpInitializer(dsym->_init->loc, e);
dsym->_init = ei;
}
Expression *exp = ei->exp;
Expression *e1 = new VarExp(dsym->loc, dsym);
if (isBlit)
exp = new BlitExp(dsym->loc, e1, exp);
else
exp = new ConstructExp(dsym->loc, e1, exp);
dsym->canassign++;
exp = expressionSemantic(exp, sc);
dsym->canassign--;
exp = exp->optimize(WANTvalue);
if (exp->op == TOKerror)
{
dsym->_init = new ErrorInitializer();
ei = NULL;
}
else
ei->exp = exp;
if (ei && dsym->isScope())
{
Expression *ex = ei->exp;
while (ex->op == TOKcomma)
ex = ((CommaExp *)ex)->e2;
if (ex->op == TOKblit || ex->op == TOKconstruct)
ex = ((AssignExp *)ex)->e2;
if (ex->op == TOKnew)
{
// See if initializer is a NewExp that can be allocated on the stack
NewExp *ne = (NewExp *)ex;
if (dsym->type->toBasetype()->ty == Tclass)
{
if (ne->newargs && ne->newargs->length > 1)
{
dsym->mynew = true;
}
else
{
ne->onstack = true;
dsym->onstack = true;
}
}
}
else if (ex->op == TOKfunction)
{
// or a delegate that doesn't escape a reference to the function
FuncDeclaration *f = ((FuncExp *)ex)->fd;
f->tookAddressOf--;
}
}
}
else
{
// Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
}
}
else if (parent->isAggregateDeclaration())
{
dsym->_scope = scx ? scx : sc->copy();
dsym->_scope->setNoFree();
}
else if (dsym->storage_class & (STCconst | STCimmutable | STCmanifest) ||
dsym->type->isConst() || dsym->type->isImmutable())
{
/* Because we may need the results of a const declaration in a
* subsequent type, such as an array dimension, before semantic2()
* gets ordinarily run, try to run semantic2() now.
* Ignore failure.
*/
if (!inferred)
{
unsigned errors = global.errors;
dsym->inuse++;
if (ei)
{
Expression *exp = ei->exp->syntaxCopy();
bool needctfe = dsym->isDataseg() || (dsym->storage_class & STCmanifest);
if (needctfe) sc = sc->startCTFE();
exp = expressionSemantic(exp, sc);
exp = resolveProperties(sc, exp);
if (needctfe) sc = sc->endCTFE();
Type *tb2 = dsym->type->toBasetype();
Type *ti = exp->type->toBasetype();
/* The problem is the following code:
* struct CopyTest {
* double x;
* this(double a) { x = a * 10.0;}
* this(this) { x += 2.0; }
* }
* const CopyTest z = CopyTest(5.3); // ok
* const CopyTest w = z; // not ok, postblit not run
* static assert(w.x == 55.0);
* because the postblit doesn't get run on the initialization of w.
*/
if (ti->ty == Tstruct)
{
StructDeclaration *sd = ((TypeStruct *)ti)->sym;
/* Look to see if initializer involves a copy constructor
* (which implies a postblit)
*/
// there is a copy constructor
// and exp is the same struct
if (sd->postblit &&
tb2->toDsymbol(NULL) == sd)
{
// The only allowable initializer is a (non-copy) constructor
if (exp->isLvalue())
dsym->error("of type struct %s uses this(this), which is not allowed in static initialization", tb2->toChars());
}
}
ei->exp = exp;
}
dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, INITinterpret);
dsym->inuse--;
if (global.errors > errors)
{
dsym->_init = new ErrorInitializer();
dsym->type = Type::terror;
}
}
else
{
dsym->_scope = scx ? scx : sc->copy();
dsym->_scope->setNoFree();
}
}
sc = sc->pop();
}
Ldtor:
/* Build code to execute destruction, if necessary
*/
dsym->edtor = dsym->callScopeDtor(sc);
if (dsym->edtor)
{
if (sc->func && dsym->storage_class & (STCstatic | STCgshared))
dsym->edtor = expressionSemantic(dsym->edtor, sc->_module->_scope);
else
dsym->edtor = expressionSemantic(dsym->edtor, sc);
#if 0 // currently disabled because of std.stdio.stdin, stdout and stderr
if (dsym->isDataseg() && !(dsym->storage_class & STCextern))
dsym->error("static storage variables cannot have destructors");
#endif
}
dsym->semanticRun = PASSsemanticdone;
if (dsym->type->toBasetype()->ty == Terror)
dsym->errors = true;
if (sc->scopesym && !sc->scopesym->isAggregateDeclaration())
{
for (ScopeDsymbol *sym = sc->scopesym; sym && dsym->endlinnum == 0;
sym = sym->parent ? sym->parent->isScopeDsymbol() : NULL)
dsym->endlinnum = sym->endlinnum;
}
}
void visit(TypeInfoDeclaration *dsym)
{
assert(dsym->linkage == LINKc);
}
void visit(Import *imp)
{
//printf("Import::semantic('%s') %s\n", toPrettyChars(), imp->id->toChars());
if (imp->semanticRun > PASSinit)
return;
if (imp->_scope)
{
sc = imp->_scope;
imp->_scope = NULL;
}
if (!sc)
return;
imp->semanticRun = PASSsemantic;
// Load if not already done so
if (!imp->mod)
{
imp->load(sc);
if (imp->mod)
imp->mod->importAll(NULL);
}
if (imp->mod)
{
// Modules need a list of each imported module
//printf("%s imports %s\n", sc->_module->toChars(), imp->mod->toChars());
sc->_module->aimports.push(imp->mod);
if (sc->explicitProtection)
imp->protection = sc->protection;
if (!imp->aliasId && !imp->names.length) // neither a selective nor a renamed import
{
ScopeDsymbol *scopesym = NULL;
if (sc->explicitProtection)
imp->protection = sc->protection.kind;
for (Scope *scd = sc; scd; scd = scd->enclosing)
{
if (!scd->scopesym)
continue;
scopesym = scd->scopesym;
break;
}
if (!imp->isstatic)
{
scopesym->importScope(imp->mod, imp->protection);
}
imp->addPackageAccess(scopesym);
}
dsymbolSemantic(imp->mod, NULL);
if (imp->mod->needmoduleinfo)
{
//printf("module4 %s because of %s\n", sc->_module->toChars(), imp->mod->toChars());
sc->_module->needmoduleinfo = 1;
}
sc = sc->push(imp->mod);
sc->protection = imp->protection;
for (size_t i = 0; i < imp->aliasdecls.length; i++)
{
AliasDeclaration *ad = imp->aliasdecls[i];
//printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), imp->aliases[i]->toChars(), imp->names[i]->toChars(), ad->_scope);
Dsymbol *sym = imp->mod->search(imp->loc, imp->names[i], IgnorePrivateImports);
if (sym)
{
if (!symbolIsVisible(sc, sym))
imp->mod->error(imp->loc, "member `%s` is not visible from module `%s`",
imp->names[i]->toChars(), sc->_module->toChars());
dsymbolSemantic(ad, sc);
// If the import declaration is in non-root module,
// analysis of the aliased symbol is deferred.
// Therefore, don't see the ad->aliassym or ad->type here.
}
else
{
Dsymbol *s = imp->mod->search_correct(imp->names[i]);
if (s)
imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toPrettyChars());
else
imp->mod->error(imp->loc, "import `%s` not found", imp->names[i]->toChars());
ad->type = Type::terror;
}
}
sc = sc->pop();
}
imp->semanticRun = PASSsemanticdone;
// object self-imports itself, so skip that (Bugzilla 7547)
// don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164)
if (global.params.moduleDeps != NULL &&
!(imp->id == Id::object && sc->_module->ident == Id::object) &&
sc->_module->ident != Id::entrypoint &&
strcmp(sc->_module->ident->toChars(), "__main") != 0)
{
/* The grammar of the file is:
* ImportDeclaration
* ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
* ModuleAliasIdentifier ] "\n"
*
* BasicImportDeclaration
* ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
* " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
*
* FilePath
* - any string with '(', ')' and '\' escaped with the '\' character
*/
OutBuffer *ob = global.params.moduleDeps;
Module* imod = sc->instantiatingModule();
if (!global.params.moduleDepsFile.length)
ob->writestring("depsImport ");
ob->writestring(imod->toPrettyChars());
ob->writestring(" (");
escapePath(ob, imod->srcfile->toChars());
ob->writestring(") : ");
// use protection instead of sc->protection because it couldn't be
// resolved yet, see the comment above
protectionToBuffer(ob, imp->protection);
ob->writeByte(' ');
if (imp->isstatic)
{
stcToBuffer(ob, STCstatic);
ob->writeByte(' ');
}
ob->writestring(": ");
if (imp->packages)
{
for (size_t i = 0; i < imp->packages->length; i++)
{
Identifier *pid = (*imp->packages)[i];
ob->printf("%s.", pid->toChars());
}
}
ob->writestring(imp->id->toChars());
ob->writestring(" (");
if (imp->mod)
escapePath(ob, imp->mod->srcfile->toChars());
else
ob->writestring("???");
ob->writeByte(')');
for (size_t i = 0; i < imp->names.length; i++)
{
if (i == 0)
ob->writeByte(':');
else
ob->writeByte(',');
Identifier *name = imp->names[i];
Identifier *alias = imp->aliases[i];
if (!alias)
{
ob->printf("%s", name->toChars());
alias = name;
}
else
ob->printf("%s=%s", alias->toChars(), name->toChars());
}
if (imp->aliasId)
ob->printf(" -> %s", imp->aliasId->toChars());
ob->writenl();
}
//printf("-Import::semantic('%s'), pkg = %p\n", imp->toChars(), imp->pkg);
}
void attribSemantic(AttribDeclaration *ad)
{
if (ad->semanticRun != PASSinit)
return;
ad->semanticRun = PASSsemantic;
Dsymbols *d = ad->include(sc);
//printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
if (d)
{
Scope *sc2 = ad->newScope(sc);
bool errors = false;
for (size_t i = 0; i < d->length; i++)
{
Dsymbol *s = (*d)[i];
dsymbolSemantic(s, sc2);
errors |= s->errors;
}
ad->errors |= errors;
if (sc2 != sc)
sc2->pop();
}
ad->semanticRun = PASSsemanticdone;
}
void visit(AttribDeclaration *atd)
{
attribSemantic(atd);
}
void visit(AnonDeclaration *scd)
{
//printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", scd);
assert(sc->parent);
Dsymbol *p = sc->parent->pastMixin();
AggregateDeclaration *ad = p->isAggregateDeclaration();
if (!ad)
{
error(scd->loc, "%s can only be a part of an aggregate, not %s %s",
scd->kind(), p->kind(), p->toChars());
scd->errors = true;
return;
}
if (scd->decl)
{
sc = sc->push();
sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared);
sc->inunion = scd->isunion;
sc->flags = 0;
for (size_t i = 0; i < scd->decl->length; i++)
{
Dsymbol *s = (*scd->decl)[i];
dsymbolSemantic(s, sc);
}
sc = sc->pop();
}
}
void visit(PragmaDeclaration *pd)
{
// Should be merged with PragmaStatement
//printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
if (pd->ident == Id::msg)
{
if (pd->args)
{
for (size_t i = 0; i < pd->args->length; i++)
{
Expression *e = (*pd->args)[i];
sc = sc->startCTFE();
e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
e = ctfeInterpretForPragmaMsg(e);
if (e->op == TOKerror)
{
errorSupplemental(pd->loc, "while evaluating pragma(msg, %s)", (*pd->args)[i]->toChars());
return;
}
StringExp *se = e->toStringExp();
if (se)
{
se = se->toUTF8(sc);
fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
}
else
fprintf(stderr, "%s", e->toChars());
}
fprintf(stderr, "\n");
}
goto Lnodecl;
}
else if (pd->ident == Id::lib)
{
if (!pd->args || pd->args->length != 1)
pd->error("string expected for library name");
else
{
StringExp *se = semanticString(sc, (*pd->args)[0], "library name");
if (!se)
goto Lnodecl;
(*pd->args)[0] = se;
char *name = (char *)mem.xmalloc(se->len + 1);
memcpy(name, se->string, se->len);
name[se->len] = 0;
if (global.params.verbose)
message("library %s", name);
if (global.params.moduleDeps && !global.params.moduleDepsFile.length)
{
OutBuffer *ob = global.params.moduleDeps;
Module *imod = sc->instantiatingModule();
ob->writestring("depsLib ");
ob->writestring(imod->toPrettyChars());
ob->writestring(" (");
escapePath(ob, imod->srcfile->toChars());
ob->writestring(") : ");
ob->writestring((char *) name);
ob->writenl();
}
mem.xfree(name);
}
goto Lnodecl;
}
else if (pd->ident == Id::startaddress)
{
if (!pd->args || pd->args->length != 1)
pd->error("function name expected for start address");
else
{
/* Bugzilla 11980:
* resolveProperties and ctfeInterpret call are not necessary.
*/
Expression *e = (*pd->args)[0];
sc = sc->startCTFE();
e = expressionSemantic(e, sc);
sc = sc->endCTFE();
(*pd->args)[0] = e;
Dsymbol *sa = getDsymbol(e);
if (!sa || !sa->isFuncDeclaration())
pd->error("function name expected for start address, not `%s`", e->toChars());
}
goto Lnodecl;
}
else if (pd->ident == Id::Pinline)
{
goto Ldecl;
}
else if (pd->ident == Id::mangle)
{
if (!pd->args)
pd->args = new Expressions();
if (pd->args->length != 1)
{
pd->error("string expected for mangled name");
pd->args->setDim(1);
(*pd->args)[0] = new ErrorExp(); // error recovery
goto Ldecl;
}
StringExp *se = semanticString(sc, (*pd->args)[0], "mangled name");
if (!se)
goto Ldecl;
(*pd->args)[0] = se; // Will be used for later
if (!se->len)
{
pd->error("zero-length string not allowed for mangled name");
goto Ldecl;
}
if (se->sz != 1)
{
pd->error("mangled name characters can only be of type char");
goto Ldecl;
}
/* Note: D language specification should not have any assumption about backend
* implementation. Ideally pragma(mangle) can accept a string of any content.
*
* Therefore, this validation is compiler implementation specific.
*/
for (size_t i = 0; i < se->len; )
{
utf8_t *p = (utf8_t *)se->string;
dchar_t c = p[i];
if (c < 0x80)
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
(c != 0 && strchr("$%().:?@[]_", c)))
{
++i;
continue;
}
else
{
pd->error("char 0x%02x not allowed in mangled name", c);
break;
}
}
if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c))
{
pd->error("%s", msg);
break;
}
if (!isUniAlpha(c))
{
pd->error("char 0x%04x not allowed in mangled name", c);
break;
}
}
}
else if (pd->ident == Id::printf || pd->ident == Id::scanf)
{
if (pd->args && pd->args->length != 0)
pd->error("takes no argument");
goto Ldecl;
}
else if (global.params.ignoreUnsupportedPragmas)
{
if (global.params.verbose)
{
/* Print unrecognized pragmas
*/
OutBuffer buf;
buf.writestring(pd->ident->toChars());
if (pd->args)
{
for (size_t i = 0; i < pd->args->length; i++)
{
Expression *e = (*pd->args)[i];
sc = sc->startCTFE();
e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
e = e->ctfeInterpret();
if (i == 0)
buf.writestring(" (");
else
buf.writeByte(',');
buf.writestring(e->toChars());
}
if (pd->args->length)
buf.writeByte(')');
}
message("pragma %s", buf.peekChars());
}
goto Lnodecl;
}
else
error(pd->loc, "unrecognized pragma(%s)", pd->ident->toChars());
Ldecl:
if (pd->decl)
{
Scope *sc2 = pd->newScope(sc);
for (size_t i = 0; i < pd->decl->length; i++)
{
Dsymbol *s = (*pd->decl)[i];
dsymbolSemantic(s, sc2);
if (pd->ident == Id::mangle)
{
assert(pd->args && pd->args->length == 1);
if (StringExp *se = (*pd->args)[0]->toStringExp())
{
char *name = (char *)mem.xmalloc(se->len + 1);
memcpy(name, se->string, se->len);
name[se->len] = 0;
unsigned cnt = setMangleOverride(s, name);
if (cnt > 1)
pd->error("can only apply to a single declaration");
}
}
}
if (sc2 != sc)
sc2->pop();
}
return;
Lnodecl:
if (pd->decl)
{
pd->error("pragma is missing closing `;`");
goto Ldecl; // do them anyway, to avoid segfaults.
}
}
void visit(StaticIfDeclaration *sid)
{
attribSemantic(sid);
}
void visit(StaticForeachDeclaration *sfd)
{
attribSemantic(sfd);
}
Dsymbols *compileIt(CompileDeclaration *cd)
{
//printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd->loc.linnum, cd->exp->toChars());
OutBuffer buf;
if (expressionsToString(buf, sc, cd->exps))
return NULL;
unsigned errors = global.errors;
const size_t len = buf.length();
const char *str = buf.extractChars();
Parser p(cd->loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
Dsymbols *d = p.parseDeclDefs(0);
if (global.errors != errors)
return NULL;
if (p.token.value != TOKeof)
{
cd->error("incomplete mixin declaration (%s)", str);
return NULL;
}
return d;
}
void visit(CompileDeclaration *cd)
{
//printf("CompileDeclaration::semantic()\n");
if (!cd->compiled)
{
cd->decl = compileIt(cd);
cd->AttribDeclaration::addMember(sc, cd->scopesym);
cd->compiled = true;
if (cd->_scope && cd->decl)
{
for (size_t i = 0; i < cd->decl->length; i++)
{
Dsymbol *s = (*cd->decl)[i];
s->setScope(cd->_scope);
}
}
}
attribSemantic(cd);
}
void visit(UserAttributeDeclaration *uad)
{
//printf("UserAttributeDeclaration::semantic() %p\n", this);
if (uad->decl && !uad->_scope)
uad->Dsymbol::setScope(sc); // for function local symbols
attribSemantic(uad);
}
void visit(StaticAssert *sa)
{
if (sa->semanticRun < PASSsemanticdone)
sa->semanticRun = PASSsemanticdone;
}
void visit(DebugSymbol *ds)
{
//printf("DebugSymbol::semantic() %s\n", ds->toChars());
if (ds->semanticRun < PASSsemanticdone)
ds->semanticRun = PASSsemanticdone;
}
void visit(VersionSymbol *vs)
{
if (vs->semanticRun < PASSsemanticdone)
vs->semanticRun = PASSsemanticdone;
}
void visit(Package *pkg)
{
if (pkg->semanticRun < PASSsemanticdone)
pkg->semanticRun = PASSsemanticdone;
}
void visit(Module *m)
{
if (m->semanticRun != PASSinit)
return;
//printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, m->toChars(), parent);
m->semanticRun = PASSsemantic;
// Note that modules get their own scope, from scratch.
// This is so regardless of where in the syntax a module
// gets imported, it is unaffected by context.
Scope *sc = m->_scope; // see if already got one from importAll()
if (!sc)
{
sc = Scope::createGlobal(m); // create root scope
}
//printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
// Pass 1 semantic routines: do public side of the definition
for (size_t i = 0; i < m->members->length; i++)
{
Dsymbol *s = (*m->members)[i];
//printf("\tModule('%s'): '%s'.semantic()\n", m->toChars(), s->toChars());
dsymbolSemantic(s, sc);
m->runDeferredSemantic();
}
if (m->userAttribDecl)
{
dsymbolSemantic(m->userAttribDecl, sc);
}
if (!m->_scope)
{
sc = sc->pop();
sc->pop(); // 2 pops because Scope::createGlobal() created 2
}
m->semanticRun = PASSsemanticdone;
//printf("-Module::semantic(this = %p, '%s'): parent = %p\n", m, m->toChars(), parent);
}
void visit(EnumDeclaration *ed)
{
//printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), ed->toChars());
//printf("EnumDeclaration::semantic() %p %s\n", ed, ed->toChars());
if (ed->semanticRun >= PASSsemanticdone)
return; // semantic() already completed
if (ed->semanticRun == PASSsemantic)
{
assert(ed->memtype);
error(ed->loc, "circular reference to enum base type %s", ed->memtype->toChars());
ed->errors = true;
ed->semanticRun = PASSsemanticdone;
return;
}
unsigned dprogress_save = Module::dprogress;
Scope *scx = NULL;
if (ed->_scope)
{
sc = ed->_scope;
scx = ed->_scope; // save so we don't make redundant copies
ed->_scope = NULL;
}
if (!sc)
return;
ed->parent = sc->parent;
ed->type = typeSemantic(ed->type, ed->loc, sc);
ed->protection = sc->protection;
if (sc->stc & STCdeprecated)
ed->isdeprecated = true;
ed->userAttribDecl = sc->userAttribDecl;
ed->semanticRun = PASSsemantic;
if (!ed->members && !ed->memtype) // enum ident;
{
ed->semanticRun = PASSsemanticdone;
return;
}
if (!ed->symtab)
ed->symtab = new DsymbolTable();
/* The separate, and distinct, cases are:
* 1. enum { ... }
* 2. enum : memtype { ... }
* 3. enum ident { ... }
* 4. enum ident : memtype { ... }
* 5. enum ident : memtype;
* 6. enum ident;
*/
if (ed->memtype)
{
ed->memtype = typeSemantic(ed->memtype, ed->loc, sc);
/* Check to see if memtype is forward referenced
*/
if (ed->memtype->ty == Tenum)
{
EnumDeclaration *sym = (EnumDeclaration *)ed->memtype->toDsymbol(sc);
if (!sym->memtype || !sym->members || !sym->symtab || sym->_scope)
{
// memtype is forward referenced, so try again later
ed->_scope = scx ? scx : sc->copy();
ed->_scope->setNoFree();
Module::addDeferredSemantic(ed);
Module::dprogress = dprogress_save;
//printf("\tdeferring %s\n", ed->toChars());
ed->semanticRun = PASSinit;
return;
}
else
// Ensure that semantic is run to detect. e.g. invalid forward references
dsymbolSemantic(sym, sc);
}
if (ed->memtype->ty == Tvoid)
{
ed->error("base type must not be void");
ed->memtype = Type::terror;
}
if (ed->memtype->ty == Terror)
{
ed->errors = true;
if (ed->members)
{
for (size_t i = 0; i < ed->members->length; i++)
{
Dsymbol *s = (*ed->members)[i];
s->errors = true; // poison all the members
}
}
ed->semanticRun = PASSsemanticdone;
return;
}
}
ed->semanticRun = PASSsemanticdone;
if (!ed->members) // enum ident : memtype;
return;
if (ed->members->length == 0)
{
ed->error("enum %s must have at least one member", ed->toChars());
ed->errors = true;
return;
}
Module::dprogress++;
Scope *sce;
if (ed->isAnonymous())
sce = sc;
else
{
sce = sc->push(ed);
sce->parent = ed;
}
sce = sce->startCTFE();
sce->setNoFree(); // needed for getMaxMinValue()
/* Each enum member gets the sce scope
*/
for (size_t i = 0; i < ed->members->length; i++)
{
EnumMember *em = (*ed->members)[i]->isEnumMember();
if (em)
em->_scope = sce;
}
if (!ed->added)
{
/* addMember() is not called when the EnumDeclaration appears as a function statement,
* so we have to do what addMember() does and install the enum members in the right symbol
* table
*/
ScopeDsymbol *scopesym = NULL;
if (ed->isAnonymous())
{
/* Anonymous enum members get added to enclosing scope.
*/
for (Scope *sct = sce; 1; sct = sct->enclosing)
{
assert(sct);
if (sct->scopesym)
{
scopesym = sct->scopesym;
if (!sct->scopesym->symtab)
sct->scopesym->symtab = new DsymbolTable();
break;
}
}
}
else
{
// Otherwise enum members are in the EnumDeclaration's symbol table
scopesym = ed;
}
for (size_t i = 0; i < ed->members->length; i++)
{
EnumMember *em = (*ed->members)[i]->isEnumMember();
if (em)
{
em->ed = ed;
em->addMember(sc, scopesym);
}
}
}
for (size_t i = 0; i < ed->members->length; i++)
{
EnumMember *em = (*ed->members)[i]->isEnumMember();
if (em)
dsymbolSemantic(em, em->_scope);
}
//printf("defaultval = %lld\n", defaultval);
//if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
//printf("members = %s\n", ed->members->toChars());
}
void visit(EnumMember *em)
{
//printf("EnumMember::semantic() %s\n", em->toChars());
if (em->errors || em->semanticRun >= PASSsemanticdone)
return;
if (em->semanticRun == PASSsemantic)
{
em->error("circular reference to enum member");
Lerrors:
em->errors = true;
em->semanticRun = PASSsemanticdone;
return;
}
assert(em->ed);
dsymbolSemantic(em->ed, sc);
if (em->ed->errors)
goto Lerrors;
if (em->errors || em->semanticRun >= PASSsemanticdone)
return;
if (em->_scope)
sc = em->_scope;
if (!sc)
return;
em->semanticRun = PASSsemantic;
em->protection = em->ed->isAnonymous() ? em->ed->protection : Prot(Prot::public_);
em->linkage = LINKd;
em->storage_class |= STCmanifest;
// https://issues.dlang.org/show_bug.cgi?id=9701
if (em->ed->isAnonymous())
{
if (em->userAttribDecl)
em->userAttribDecl->userAttribDecl = em->ed->userAttribDecl;
else
em->userAttribDecl = em->ed->userAttribDecl;
}
// The first enum member is special
bool first = (em == (*em->ed->members)[0]);
if (em->origType)
{
em->origType = typeSemantic(em->origType, em->loc, sc);
em->type = em->origType;
assert(em->value()); // "type id;" is not a valid enum member declaration
}
if (em->value())
{
Expression *e = em->value();
assert(e->dyncast() == DYNCAST_EXPRESSION);
e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
e = e->ctfeInterpret();
if (e->op == TOKerror)
goto Lerrors;
if (first && !em->ed->memtype && !em->ed->isAnonymous())
{
em->ed->memtype = e->type;
if (em->ed->memtype->ty == Terror)
{
em->ed->errors = true;
goto Lerrors;
}
if (em->ed->memtype->ty != Terror)
{
/* Bugzilla 11746: All of named enum members should have same type
* with the first member. If the following members were referenced
* during the first member semantic, their types should be unified.
*/
for (size_t i = 0; i < em->ed->members->length; i++)
{
EnumMember *enm = (*em->ed->members)[i]->isEnumMember();
if (!enm || enm == em || enm->semanticRun < PASSsemanticdone || enm->origType)
continue;
//printf("[%d] enm = %s, enm->semanticRun = %d\n", i, enm->toChars(), enm->semanticRun);
Expression *ev = enm->value();
ev = ev->implicitCastTo(sc, em->ed->memtype);
ev = ev->ctfeInterpret();
ev = ev->castTo(sc, em->ed->type);
if (ev->op == TOKerror)
em->ed->errors = true;
enm->value() = ev;
}
if (em->ed->errors)
{
em->ed->memtype = Type::terror;
goto Lerrors;
}
}
}
if (em->ed->memtype && !em->origType)
{
e = e->implicitCastTo(sc, em->ed->memtype);
e = e->ctfeInterpret();
// save origValue for better json output
em->origValue = e;
if (!em->ed->isAnonymous())
{
e = e->castTo(sc, em->ed->type);
e = e->ctfeInterpret();
}
}
else if (em->origType)
{
e = e->implicitCastTo(sc, em->origType);
e = e->ctfeInterpret();
assert(em->ed->isAnonymous());
// save origValue for better json output
em->origValue = e;
}
em->value() = e;
}
else if (first)
{
Type *t;
if (em->ed->memtype)
t = em->ed->memtype;
else
{
t = Type::tint32;
if (!em->ed->isAnonymous())
em->ed->memtype = t;
}
Expression *e = new IntegerExp(em->loc, 0, Type::tint32);
e = e->implicitCastTo(sc, t);
e = e->ctfeInterpret();
// save origValue for better json output
em->origValue = e;
if (!em->ed->isAnonymous())
{
e = e->castTo(sc, em->ed->type);
e = e->ctfeInterpret();
}
em->value() = e;
}
else
{
/* Find the previous enum member,
* and set this to be the previous value + 1
*/
EnumMember *emprev = NULL;
for (size_t i = 0; i < em->ed->members->length; i++)
{
EnumMember *enm = (*em->ed->members)[i]->isEnumMember();
if (enm)
{
if (enm == em)
break;
emprev = enm;
}
}
assert(emprev);
if (emprev->semanticRun < PASSsemanticdone) // if forward reference
dsymbolSemantic(emprev, emprev->_scope); // resolve it
if (emprev->errors)
goto Lerrors;
Expression *eprev = emprev->value();
Type *tprev = eprev->type->equals(em->ed->type) ? em->ed->memtype : eprev->type;
Expression *emax = tprev->getProperty(em->ed->loc, Id::max, 0);
emax = expressionSemantic(emax, sc);
emax = emax->ctfeInterpret();
// Set value to (eprev + 1).
// But first check that (eprev != emax)
assert(eprev);
Expression *e = new EqualExp(TOKequal, em->loc, eprev, emax);
e = expressionSemantic(e, sc);
e = e->ctfeInterpret();
if (e->toInteger())
{
em->error("initialization with (%s.%s + 1) causes overflow for type `%s`", emprev->ed->toChars(), emprev->toChars(), em->ed->type->toBasetype()->toChars());
goto Lerrors;
}
// Now set e to (eprev + 1)
e = new AddExp(em->loc, eprev, new IntegerExp(em->loc, 1, Type::tint32));
e = expressionSemantic(e, sc);
e = e->castTo(sc, eprev->type);
e = e->ctfeInterpret();
// save origValue (without cast) for better json output
if (e->op != TOKerror) // avoid duplicate diagnostics
{
assert(emprev->origValue);
em->origValue = new AddExp(em->loc, emprev->origValue, new IntegerExp(em->loc, 1, Type::tint32));
em->origValue = expressionSemantic(em->origValue, sc);
em->origValue = em->origValue->ctfeInterpret();
}
if (e->op == TOKerror)
goto Lerrors;
if (e->type->isfloating())
{
// Check that e != eprev (not always true for floats)
Expression *etest = new EqualExp(TOKequal, em->loc, e, eprev);
etest = expressionSemantic(etest, sc);
etest = etest->ctfeInterpret();
if (etest->toInteger())
{
em->error("has inexact value, due to loss of precision");
goto Lerrors;
}
}
em->value() = e;
}
if (!em->origType)
em->type = em->value()->type;
assert(em->origValue);
em->semanticRun = PASSsemanticdone;
}
void visit(TemplateDeclaration *tempdecl)
{
if (tempdecl->semanticRun != PASSinit)
return; // semantic() already run
// Remember templates defined in module object that we need to know about
if (sc->_module && sc->_module->ident == Id::object)
{
if (tempdecl->ident == Id::RTInfo)
Type::rtinfo = tempdecl;
}
/* Remember Scope for later instantiations, but make
* a copy since attributes can change.
*/
if (!tempdecl->_scope)
{
tempdecl->_scope = sc->copy();
tempdecl->_scope->setNoFree();
}
tempdecl->semanticRun = PASSsemantic;
tempdecl->parent = sc->parent;
tempdecl->protection = sc->protection;
tempdecl->isstatic = tempdecl->toParent()->isModule() || (tempdecl->_scope->stc & STCstatic);
if (!tempdecl->isstatic)
{
if (AggregateDeclaration *ad = tempdecl->parent->pastMixin()->isAggregateDeclaration())
ad->makeNested();
}
// Set up scope for parameters
ScopeDsymbol *paramsym = new ScopeDsymbol();
paramsym->parent = tempdecl->parent;
Scope *paramscope = sc->push(paramsym);
paramscope->stc = 0;
if (global.params.doDocComments)
{
tempdecl->origParameters = new TemplateParameters();
tempdecl->origParameters->setDim(tempdecl->parameters->length);
for (size_t i = 0; i < tempdecl->parameters->length; i++)
{
TemplateParameter *tp = (*tempdecl->parameters)[i];
(*tempdecl->origParameters)[i] = tp->syntaxCopy();
}
}
for (size_t i = 0; i < tempdecl->parameters->length; i++)
{
TemplateParameter *tp = (*tempdecl->parameters)[i];
if (!tp->declareParameter(paramscope))
{
error(tp->loc, "parameter `%s` multiply defined", tp->ident->toChars());
tempdecl->errors = true;
}
if (!tpsemantic(tp, paramscope, tempdecl->parameters))
{
tempdecl->errors = true;
}
if (i + 1 != tempdecl->parameters->length && tp->isTemplateTupleParameter())
{
tempdecl->error("template tuple parameter must be last one");
tempdecl->errors = true;
}
}
/* Calculate TemplateParameter::dependent
*/
TemplateParameters tparams;
tparams.setDim(1);
for (size_t i = 0; i < tempdecl->parameters->length; i++)
{
TemplateParameter *tp = (*tempdecl->parameters)[i];
tparams[0] = tp;
for (size_t j = 0; j < tempdecl->parameters->length; j++)
{
// Skip cases like: X(T : T)
if (i == j)
continue;
if (TemplateTypeParameter *ttp = (*tempdecl->parameters)[j]->isTemplateTypeParameter())
{
if (reliesOnTident(ttp->specType, &tparams))
tp->dependent = true;
}
else if (TemplateAliasParameter *tap = (*tempdecl->parameters)[j]->isTemplateAliasParameter())
{
if (reliesOnTident(tap->specType, &tparams) ||
reliesOnTident(isType(tap->specAlias), &tparams))
{
tp->dependent = true;
}
}
}
}
paramscope->pop();
// Compute again
tempdecl->onemember = NULL;
if (tempdecl->members)
{
Dsymbol *s;
if (Dsymbol::oneMembers(tempdecl->members, &s, tempdecl->ident) && s)
{
tempdecl->onemember = s;
s->parent = tempdecl;
}
}
/* BUG: should check:
* o no virtual functions or non-static data members of classes
*/
tempdecl->semanticRun = PASSsemanticdone;
}
void visit(TemplateInstance *ti)
{
templateInstanceSemantic(ti, sc, NULL);
}
void visit(TemplateMixin *tm)
{
if (tm->semanticRun != PASSinit)
{
// When a class/struct contains mixin members, and is done over
// because of forward references, never reach here so semanticRun
// has been reset to PASSinit.
return;
}
tm->semanticRun = PASSsemantic;
Scope *scx = NULL;
if (tm->_scope)
{
sc = tm->_scope;
scx = tm->_scope; // save so we don't make redundant copies
tm->_scope = NULL;
}
/* Run semantic on each argument, place results in tiargs[],
* then find best match template with tiargs
*/
if (!tm->findTempDecl(sc) ||
!tm->semanticTiargs(sc) ||
!tm->findBestMatch(sc, NULL))
{
if (tm->semanticRun == PASSinit) // forward reference had occured
{
//printf("forward reference - deferring\n");
tm->_scope = scx ? scx : sc->copy();
tm->_scope->setNoFree();
Module::addDeferredSemantic(tm);
return;
}
tm->inst = tm;
tm->errors = true;
return; // error recovery
}
TemplateDeclaration *tempdecl = tm->tempdecl->isTemplateDeclaration();
assert(tempdecl);
if (!tm->ident)
{
/* Assign scope local unique identifier, as same as lambdas.
*/
const char *s = "__mixin";
if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
{
tm->symtab = func->localsymtab;
if (tm->symtab)
{
// Inside template constraint, symtab is not set yet.
goto L1;
}
}
else
{
tm->symtab = sc->parent->isScopeDsymbol()->symtab;
L1:
assert(tm->symtab);
int num = (int)dmd_aaLen(tm->symtab->tab) + 1;
tm->ident = Identifier::generateId(s, num);
tm->symtab->insert(tm);
}
}
tm->inst = tm;
tm->parent = sc->parent;
/* Detect recursive mixin instantiations.
*/
for (Dsymbol *s = tm->parent; s; s = s->parent)
{
//printf("\ts = '%s'\n", s->toChars());
TemplateMixin *tmix = s->isTemplateMixin();
if (!tmix || tempdecl != tmix->tempdecl)
continue;
/* Different argument list lengths happen with variadic args
*/
if (tm->tiargs->length != tmix->tiargs->length)
continue;
for (size_t i = 0; i < tm->tiargs->length; i++)
{
RootObject *o = (*tm->tiargs)[i];
Type *ta = isType(o);
Expression *ea = isExpression(o);
Dsymbol *sa = isDsymbol(o);
RootObject *tmo = (*tmix->tiargs)[i];
if (ta)
{
Type *tmta = isType(tmo);
if (!tmta)
goto Lcontinue;
if (!ta->equals(tmta))
goto Lcontinue;
}
else if (ea)
{
Expression *tme = isExpression(tmo);
if (!tme || !ea->equals(tme))
goto Lcontinue;
}
else if (sa)
{
Dsymbol *tmsa = isDsymbol(tmo);
if (sa != tmsa)
goto Lcontinue;
}
else
assert(0);
}
tm->error("recursive mixin instantiation");
return;
Lcontinue:
continue;
}
// Copy the syntax trees from the TemplateDeclaration
tm->members = Dsymbol::arraySyntaxCopy(tempdecl->members);
if (!tm->members)
return;
tm->symtab = new DsymbolTable();
for (Scope *sce = sc; 1; sce = sce->enclosing)
{
ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
if (sds)
{
sds->importScope(tm, Prot(Prot::public_));
break;
}
}
Scope *scy = sc->push(tm);
scy->parent = tm;
tm->argsym = new ScopeDsymbol();
tm->argsym->parent = scy->parent;
Scope *argscope = scy->push(tm->argsym);
unsigned errorsave = global.errors;
// Declare each template parameter as an alias for the argument type
tm->declareParameters(argscope);
// Add members to enclosing scope, as well as this scope
for (size_t i = 0; i < tm->members->length; i++)
{
Dsymbol *s = (*tm->members)[i];
s->addMember(argscope, tm);
//printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym);
//printf("s->parent = %s\n", s->parent->toChars());
}
// Do semantic() analysis on template instance members
Scope *sc2 = argscope->push(tm);
//size_t deferred_dim = Module::deferred.length;
static int nest;
//printf("%d\n", nest);
if (++nest > global.recursionLimit)
{
global.gag = 0; // ensure error message gets printed
tm->error("recursive expansion");
fatal();
}
for (size_t i = 0; i < tm->members->length; i++)
{
Dsymbol *s = (*tm->members)[i];
s->setScope(sc2);
}
for (size_t i = 0; i < tm->members->length; i++)
{
Dsymbol *s = (*tm->members)[i];
s->importAll(sc2);
}
for (size_t i = 0; i < tm->members->length; i++)
{
Dsymbol *s = (*tm->members)[i];
dsymbolSemantic(s, sc2);
}
nest--;
/* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols.
* Because the members would already call Module::addDeferredSemantic() for themselves.
* See Struct, Class, Interface, and EnumDeclaration::semantic().
*/
//if (!sc->func && Module::deferred.length > deferred_dim) {}
AggregateDeclaration *ad = tm->toParent()->isAggregateDeclaration();
if (sc->func && !ad)
{
semantic2(tm, sc2);
semantic3(tm, sc2);
}
// Give additional context info if error occurred during instantiation
if (global.errors != errorsave)
{
tm->error("error instantiating");
tm->errors = true;
}
sc2->pop();
argscope->pop();
scy->pop();
}
void visit(Nspace *ns)
{
if (ns->semanticRun != PASSinit)
return;
if (ns->_scope)
{
sc = ns->_scope;
ns->_scope = NULL;
}
if (!sc)
return;
ns->semanticRun = PASSsemantic;
ns->parent = sc->parent;
if (ns->members)
{
assert(sc);
sc = sc->push(ns);
sc->linkage = LINKcpp; // note that namespaces imply C++ linkage
sc->parent = ns;
for (size_t i = 0; i < ns->members->length; i++)
{
Dsymbol *s = (*ns->members)[i];
s->importAll(sc);
}
for (size_t i = 0; i < ns->members->length; i++)
{
Dsymbol *s = (*ns->members)[i];
dsymbolSemantic(s, sc);
}
sc->pop();
}
ns->semanticRun = PASSsemanticdone;
}
private:
static bool isPointerToChar(Parameter *p)
{
if (TypePointer *tptr = p->type->isTypePointer())
{
return tptr->next->ty == Tchar;
}
return false;
}
static bool isVa_list(Parameter *p, FuncDeclaration *funcdecl, Scope *sc)
{
return p->type->equals(target.va_listType(funcdecl->loc, sc));
}
public:
void funcDeclarationSemantic(FuncDeclaration *funcdecl)
{
TypeFunction *f;
AggregateDeclaration *ad;
InterfaceDeclaration *id;
if (funcdecl->semanticRun != PASSinit && funcdecl->isFuncLiteralDeclaration())
{
/* Member functions that have return types that are
* forward references can have semantic() run more than
* once on them.
* See test\interface2.d, test20
*/
return;
}
if (funcdecl->semanticRun >= PASSsemanticdone)
return;
assert(funcdecl->semanticRun <= PASSsemantic);
funcdecl->semanticRun = PASSsemantic;
if (funcdecl->_scope)
{
sc = funcdecl->_scope;
funcdecl->_scope = NULL;
}
if (!sc || funcdecl->errors)
return;
funcdecl->parent = sc->parent;
Dsymbol *parent = funcdecl->toParent();
funcdecl->foverrides.setDim(0); // reset in case semantic() is being retried for this function
funcdecl->storage_class |= sc->stc & ~STCref;
ad = funcdecl->isThis();
// Don't nest structs b/c of generated methods which should not access the outer scopes.
// https://issues.dlang.org/show_bug.cgi?id=16627
if (ad && !funcdecl->generated)
{
funcdecl->storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized);
ad->makeNested();
}
if (sc->func)
funcdecl->storage_class |= sc->func->storage_class & STCdisable;
// Remove prefix storage classes silently.
if ((funcdecl->storage_class & STC_TYPECTOR) && !(ad || funcdecl->isNested()))
funcdecl->storage_class &= ~STC_TYPECTOR;
//printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", funcdecl->storage_class, sc->stc, Declaration::isFinal());
FuncLiteralDeclaration *fld = funcdecl->isFuncLiteralDeclaration();
if (fld && fld->treq)
{
Type *treq = fld->treq;
assert(treq->nextOf()->ty == Tfunction);
if (treq->ty == Tdelegate)
fld->tok = TOKdelegate;
else if (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)
fld->tok = TOKfunction;
else
assert(0);
funcdecl->linkage = treq->nextOf()->toTypeFunction()->linkage;
}
else
funcdecl->linkage = sc->linkage;
funcdecl->inlining = sc->inlining;
funcdecl->protection = sc->protection;
funcdecl->userAttribDecl = sc->userAttribDecl;
if (!funcdecl->originalType)
funcdecl->originalType = funcdecl->type->syntaxCopy();
if (funcdecl->type->ty != Tfunction)
{
if (funcdecl->type->ty != Terror)
{
funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars());
funcdecl->type = Type::terror;
}
funcdecl->errors = true;
return;
}
if (!funcdecl->type->deco)
{
sc = sc->push();
sc->stc |= funcdecl->storage_class & (STCdisable | STCdeprecated); // forward to function type
TypeFunction *tf = funcdecl->type->toTypeFunction();
if (sc->func)
{
/* If the nesting parent is pure without inference,
* then this function defaults to pure too.
*
* auto foo() pure {
* auto bar() {} // become a weak purity funciton
* class C { // nested class
* auto baz() {} // become a weak purity funciton
* }
*
* static auto boo() {} // typed as impure
* // Even though, boo cannot call any impure functions.
* // See also Expression::checkPurity().
* }
*/
if (tf->purity == PUREimpure && (funcdecl->isNested() || funcdecl->isThis()))
{
FuncDeclaration *fd = NULL;
for (Dsymbol *p = funcdecl->toParent2(); p; p = p->toParent2())
{
if (AggregateDeclaration *adx = p->isAggregateDeclaration())
{
if (adx->isNested())
continue;
break;
}
if ((fd = p->isFuncDeclaration()) != NULL)
break;
}
/* If the parent's purity is inferred, then this function's purity needs
* to be inferred first.
*/
if (fd && fd->isPureBypassingInference() >= PUREweak &&
!funcdecl->isInstantiated())
{
tf->purity = PUREfwdref; // default to pure
}
}
}
if (tf->isref) sc->stc |= STCref;
if (tf->isscope) sc->stc |= STCscope;
if (tf->isnothrow) sc->stc |= STCnothrow;
if (tf->isnogc) sc->stc |= STCnogc;
if (tf->isproperty) sc->stc |= STCproperty;
if (tf->purity == PUREfwdref) sc->stc |= STCpure;
if (tf->trust != TRUSTdefault)
sc->stc &= ~(STCsafe | STCsystem | STCtrusted);
if (tf->trust == TRUSTsafe) sc->stc |= STCsafe;
if (tf->trust == TRUSTsystem) sc->stc |= STCsystem;
if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted;
if (funcdecl->isCtorDeclaration())
{
sc->flags |= SCOPEctor;
Type *tret = ad->handleType();
assert(tret);
tret = tret->addStorageClass(funcdecl->storage_class | sc->stc);
tret = tret->addMod(funcdecl->type->mod);
tf->next = tret;
if (ad->isStructDeclaration())
sc->stc |= STCref;
}
// 'return' on a non-static class member function implies 'scope' as well
if (ad && ad->isClassDeclaration() && (tf->isreturn || sc->stc & STCreturn) && !(sc->stc & STCstatic))
sc->stc |= STCscope;
// If 'this' has no pointers, remove 'scope' as it has no meaning
if (sc->stc & STCscope && ad && ad->isStructDeclaration() && !ad->type->hasPointers())
{
sc->stc &= ~STCscope;
tf->isscope = false;
}
sc->linkage = funcdecl->linkage;
if (!tf->isNaked() && !(funcdecl->isThis() || funcdecl->isNested()))
{
OutBuffer buf;
MODtoBuffer(&buf, tf->mod);
funcdecl->error("without `this` cannot be %s", buf.peekChars());
tf->mod = 0; // remove qualifiers
}
/* Apply const, immutable, wild and shared storage class
* to the function type. Do this before type semantic.
*/
StorageClass stc = funcdecl->storage_class;
if (funcdecl->type->isImmutable())
stc |= STCimmutable;
if (funcdecl->type->isConst())
stc |= STCconst;
if (funcdecl->type->isShared() || funcdecl->storage_class & STCsynchronized)
stc |= STCshared;
if (funcdecl->type->isWild())
stc |= STCwild;
switch (stc & STC_TYPECTOR)
{
case STCimmutable:
case STCimmutable | STCconst:
case STCimmutable | STCwild:
case STCimmutable | STCwild | STCconst:
case STCimmutable | STCshared:
case STCimmutable | STCshared | STCconst:
case STCimmutable | STCshared | STCwild:
case STCimmutable | STCshared | STCwild | STCconst:
// Don't use immutableOf(), as that will do a merge()
funcdecl->type = funcdecl->type->makeImmutable();
break;
case STCconst:
funcdecl->type = funcdecl->type->makeConst();
break;
case STCwild:
funcdecl->type = funcdecl->type->makeWild();
break;
case STCwild | STCconst:
funcdecl->type = funcdecl->type->makeWildConst();
break;
case STCshared:
funcdecl->type = funcdecl->type->makeShared();
break;
case STCshared | STCconst:
funcdecl->type = funcdecl->type->makeSharedConst();
break;
case STCshared | STCwild:
funcdecl->type = funcdecl->type->makeSharedWild();
break;
case STCshared | STCwild | STCconst:
funcdecl->type = funcdecl->type->makeSharedWildConst();
break;
case 0:
break;
default:
assert(0);
}
funcdecl->type = typeSemantic(funcdecl->type, funcdecl->loc, sc);
sc = sc->pop();
}
if (funcdecl->type->ty != Tfunction)
{
if (funcdecl->type->ty != Terror)
{
funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars());
funcdecl->type = Type::terror;
}
funcdecl->errors = true;
return;
}
else
{
// Merge back function attributes into 'originalType'.
// It's used for mangling, ddoc, and json output.
TypeFunction *tfo = funcdecl->originalType->toTypeFunction();
TypeFunction *tfx = funcdecl->type->toTypeFunction();
tfo->mod = tfx->mod;
tfo->isscope = tfx->isscope;
tfo->isscopeinferred = tfx->isscopeinferred;
tfo->isref = tfx->isref;
tfo->isnothrow = tfx->isnothrow;
tfo->isnogc = tfx->isnogc;
tfo->isproperty = tfx->isproperty;
tfo->purity = tfx->purity;
tfo->trust = tfx->trust;
funcdecl->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
}
f = (TypeFunction *)funcdecl->type;
if ((funcdecl->storage_class & STCauto) && !f->isref && !funcdecl->inferRetType)
funcdecl->error("storage class `auto` has no effect if return type is not inferred");
/* Functions can only be 'scope' if they have a 'this'
*/
if (f->isscope && !funcdecl->isNested() && !ad)
{
funcdecl->error("functions cannot be scope");
}
if (f->isreturn && !funcdecl->needThis() && !funcdecl->isNested())
{
/* Non-static nested functions have a hidden 'this' pointer to which
* the 'return' applies
*/
funcdecl->error("static member has no `this` to which `return` can apply");
}
if (funcdecl->isAbstract() && !funcdecl->isVirtual())
{
const char *sfunc;
if (funcdecl->isStatic())
sfunc = "static";
else if (funcdecl->protection.kind