d/dscope.o \
d/dstruct.o \
d/dsymbol.o \
+ d/dsymbolsem.o \
d/dtemplate.o \
d/dversion.o \
d/entity.o \
d/rootobject.o \
d/safe.o \
d/sapply.o \
+ d/semantic2.o \
+ d/semantic3.o \
d/sideeffect.o \
d/speller.o \
d/statement.o \
d/staticassert.o \
d/staticcond.o \
d/stringtable.o \
+ d/templateparamsem.o \
d/tokens.o \
d/traits.o \
d/typesem.o \
{
m->importedFrom = m;
m->importAll (NULL);
- m->semantic (NULL);
- m->semantic2 (NULL);
- m->semantic3 (NULL);
+ dsymbolSemantic (m, NULL);
+ semantic2 (m, NULL);
+ semantic3 (m, NULL);
d_add_entrypoint_module (m, sc->_module);
}
if (global.params.verbose)
message ("semantic %s", m->toChars ());
- m->semantic (NULL);
+ dsymbolSemantic (m, NULL);
}
/* Do deferred semantic analysis. */
if (global.params.verbose)
message ("semantic2 %s", m->toChars ());
- m->semantic2 (NULL);
+ semantic2 (m, NULL);
}
Module::runDeferredSemantic2 ();
if (global.params.verbose)
message ("semantic3 %s", m->toChars ());
- m->semantic3 (NULL);
+ semantic3 (m, NULL);
}
Module::runDeferredSemantic3 ();
-46133f76172c26c89e2ebf9cd058cd1f1e8807ed
+7132b3537dc27cb353da75798082ffe7ea3d69a6
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
/* 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.
/* 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.
AggregateDeclaration(Loc loc, Identifier *id);
virtual Scope *newScope(Scope *sc);
void setScope(Scope *sc);
- void semantic2(Scope *sc);
- void semantic3(Scope *sc);
bool determineFields();
bool determineSize(Loc loc);
virtual void finalizeSize() = 0;
StructDeclaration(Loc loc, Identifier *id, bool inObject);
static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
Dsymbol *syntaxCopy(Dsymbol *s);
- void semantic(Scope *sc);
void semanticTypeInfoMembers();
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
const char *kind() const;
static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
- void semantic(Scope *sc);
bool isBaseOf2(ClassDeclaration *cd);
#define OFFSET_RUNTIME 0x76543210
bool hasMonitor();
bool isFuncHidden(FuncDeclaration *fd);
FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
- void interfaceSemantic(Scope *sc);
bool isCOMclass() const;
virtual bool isCOMinterface() const;
bool isCPPclass() const;
InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
- void semantic(Scope *sc);
bool isBaseOf(ClassDeclaration *cd, int *poffset);
bool isBaseOf(BaseClass *bc, int *poffset);
const char *kind() const;
/* Compiler implementation of the D programming language
- * Copyright (C) 2009-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2009-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.
#include "dsymbol.h"
#include "mtype.h"
#include "declaration.h"
+#include "expression.h"
#include "tokens.h"
-Expression *semantic(Expression *e, Scope *sc);
-
Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag)
{
AggregateDeclaration *ad = isAggregate(e->type);
Loc loc = e->loc;
Type *tthis = (e->op == TOKtype ? e->type : NULL);
e = new DotIdExp(loc, e, ad->aliasthis->ident);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (tthis && ad->aliasthis->needThis())
{
if (e->op == TOKvar)
L1:
e = new TypeExp(loc, new TypeTypeof(loc, e));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
e = resolveProperties(sc, e);
return new AliasThis(loc, ident);
}
-void AliasThis::semantic(Scope *sc)
-{
- if (semanticRun != PASSinit)
- return;
-
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
-
- if (!sc)
- return;
-
- semanticRun = PASSsemantic;
-
- Dsymbol *p = sc->parent->pastMixin();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- ::error(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(loc, ident);
- if (!s)
- {
- s = sc->search(loc, ident, NULL);
- if (s)
- ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
- else
- ::error(loc, "undefined identifier %s", ident->toChars());
- return;
- }
- else if (ad->aliasthis && s != ad->aliasthis)
- {
- ::error(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(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars());
- }
- }
-
- ad->aliasthis = s;
- semanticRun = PASSsemanticdone;
-}
-
const char *AliasThis::kind() const
{
return "alias this";
/* Compiler implementation of the D programming language
- * Copyright (C) 2009-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2009-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.
AliasThis(Loc loc, Identifier *ident);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
const char *kind() const;
AliasThis *isAliasThis() { return this; }
void accept(Visitor *v) { v->visit(this); }
/* 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.
/* 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.
void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Expression *e, Parameters *fparams);
-Expression *semantic(Expression *e, Scope *sc);
/**************************************
* Hash table of array op functions already generated or known about.
sc->parent = sc->_module->importedFrom;
sc->stc = 0;
sc->linkage = LINKc;
- fd->semantic(sc);
- fd->semantic2(sc);
+ dsymbolSemantic(fd, sc);
+ semantic2(fd, sc);
unsigned errors = global.startGagging();
- fd->semantic3(sc);
+ semantic3(fd, sc);
if (global.endGagging(errors))
{
fd->type = Type::terror;
Expression *ev = new VarExp(e->loc, fd);
Expression *ec = new CallExp(e->loc, ev, arguments);
- return semantic(ec, sc);
+ return expressionSemantic(ec, sc);
}
Expression *arrayOp(BinAssignExp *e, Scope *sc)
/* Compiler implementation of the D programming language
- * Copyright (C) 2006-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2006-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.
/* 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.
/* 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.
#include "mtype.h"
bool definitelyValueParameter(Expression *e);
-Expression *semantic(Expression *e, Scope *sc);
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
Dsymbols *makeTupleForeachStaticDecl(Scope *sc, ForeachStatement *fs, Dsymbols *dbody, bool needExpansion);
/********************************* AttribDeclaration ****************************/
}
}
-void AttribDeclaration::semantic(Scope *sc)
-{
- if (semanticRun != PASSinit)
- return;
- semanticRun = PASSsemantic;
- Dsymbols *d = include(sc);
-
- //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
- if (d)
- {
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->semantic(sc2);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
- semanticRun = PASSsemanticdone;
-}
-
-void AttribDeclaration::semantic2(Scope *sc)
-{
- Dsymbols *d = include(sc);
-
- if (d)
- {
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->semantic2(sc2);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
-}
-
-void AttribDeclaration::semantic3(Scope *sc)
-{
- Dsymbols *d = include(sc);
-
- if (d)
- {
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->semantic3(sc2);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
-}
-
void AttribDeclaration::addComment(const utf8_t *comment)
{
//printf("AttribDeclaration::addComment %s\n", comment);
return AttribDeclaration::setScope(sc);
}
-/**
- * Run the DeprecatedDeclaration's semantic2 phase then its members.
- *
- * The message set via a `DeprecatedDeclaration` can be either of:
- * - a string literal
- * - an enum
- * - a static immutable
- * So we need to call ctfe to resolve it.
- * Afterward forwards to the members' semantic2.
- */
-void DeprecatedDeclaration::semantic2(Scope *sc)
-{
- getMessage();
- StorageClassDeclaration::semantic2(sc);
-}
-
const char *DeprecatedDeclaration::getMessage()
{
if (Scope *sc = _scope)
_scope = NULL;
sc = sc->startCTFE();
- msg = ::semantic(msg, sc);
+ msg = expressionSemantic(msg, sc);
msg = resolveProperties(sc, msg);
sc = sc->endCTFE();
msg = msg->ctfeInterpret();
if (StringExp *se = msg->toStringExp())
msgstr = (char *)se->string;
else
- msg->error("compile time constant expected, not '%s'", msg->toChars());
+ msg->error("compile time constant expected, not `%s`", msg->toChars());
}
return msgstr;
}
Scope *ProtDeclaration::newScope(Scope *sc)
{
if (pkg_identifiers)
- semantic(sc);
+ dsymbolSemantic(this, sc);
return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
this->protection, 1, sc->aligndecl,
sc->inlining);
Module *m = sc->_module;
Package* pkg = m->parent ? m->parent->isPackage() : NULL;
if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
- error("does not bind to one of ancestor packages of module '%s'",
+ error("does not bind to one of ancestor packages of module `%s`",
m->toPrettyChars(true));
}
sc->inlining);
}
-void AlignDeclaration::semantic2(Scope *sc)
-{
- getAlignment(sc);
- AttribDeclaration::semantic2(sc);
-}
-
structalign_t AlignDeclaration::getAlignment(Scope *sc)
{
if (salign != 0)
return salign = STRUCTALIGN_DEFAULT;
sc = sc->startCTFE();
- ealign = ::semantic(ealign, sc);
+ ealign = expressionSemantic(ealign, sc);
ealign = resolveProperties(sc, ealign);
sc = sc->endCTFE();
ealign = ealign->ctfeInterpret();
AttribDeclaration::setScope(sc);
}
-void AnonDeclaration::semantic(Scope *sc)
-{
- //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
-
- assert(sc->parent);
-
- Dsymbol *p = sc->parent->pastMixin();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- ::error(loc, "%s can only be a part of an aggregate, not %s %s",
- kind(), p->kind(), p->toChars());
- errors = true;
- return;
- }
-
- if (decl)
- {
- sc = sc->push();
- sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared);
- sc->inunion = isunion;
- sc->flags = 0;
-
- for (size_t i = 0; i < decl->length; i++)
- {
- Dsymbol *s = (*decl)[i];
- s->semantic(sc);
- }
- sc = sc->pop();
- }
-}
-
void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
{
//printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
return sc;
}
-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;
-}
-
-void PragmaDeclaration::semantic(Scope *sc)
-{
- // Should be merged with PragmaStatement
-
- //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
- if (ident == Id::msg)
- {
- if (args)
- {
- for (size_t i = 0; i < args->length; i++)
- {
- Expression *e = (*args)[i];
-
- sc = sc->startCTFE();
- e = ::semantic(e, sc);
- e = resolveProperties(sc, e);
- sc = sc->endCTFE();
-
- // pragma(msg) is allowed to contain types as well as expressions
- e = ctfeInterpretForPragmaMsg(e);
- if (e->op == TOKerror)
- {
- errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*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 (ident == Id::lib)
- {
- if (!args || args->length != 1)
- error("string expected for library name");
- else
- {
- StringExp *se = semanticString(sc, (*args)[0], "library name");
- if (!se)
- goto Lnodecl;
- (*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 (ident == Id::startaddress)
- {
- if (!args || args->length != 1)
- error("function name expected for start address");
- else
- {
- /* Bugzilla 11980:
- * resolveProperties and ctfeInterpret call are not necessary.
- */
- Expression *e = (*args)[0];
-
- sc = sc->startCTFE();
- e = ::semantic(e, sc);
- sc = sc->endCTFE();
-
- (*args)[0] = e;
- Dsymbol *sa = getDsymbol(e);
- if (!sa || !sa->isFuncDeclaration())
- error("function name expected for start address, not '%s'", e->toChars());
- }
- goto Lnodecl;
- }
- else if (ident == Id::Pinline)
- {
- goto Ldecl;
- }
- else if (ident == Id::mangle)
- {
- if (!args)
- args = new Expressions();
- if (args->length != 1)
- {
- error("string expected for mangled name");
- args->setDim(1);
- (*args)[0] = new ErrorExp(); // error recovery
- goto Ldecl;
- }
-
- StringExp *se = semanticString(sc, (*args)[0], "mangled name");
- if (!se)
- goto Ldecl;
- (*args)[0] = se; // Will be used for later
-
- if (!se->len)
- {
- error("zero-length string not allowed for mangled name");
- goto Ldecl;
- }
- if (se->sz != 1)
- {
- 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
- {
- 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))
- {
- error("%s", msg);
- break;
- }
-
- if (!isUniAlpha(c))
- {
- error("char 0x%04x not allowed in mangled name", c);
- break;
- }
- }
- }
- else if (global.params.ignoreUnsupportedPragmas)
- {
- if (global.params.verbose)
- {
- /* Print unrecognized pragmas
- */
- OutBuffer buf;
- buf.writestring(ident->toChars());
- if (args)
- {
- for (size_t i = 0; i < args->length; i++)
- {
- Expression *e = (*args)[i];
-
- sc = sc->startCTFE();
- e = ::semantic(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 (args->length)
- buf.writeByte(')');
- }
- message("pragma %s", buf.peekChars());
- }
- goto Lnodecl;
- }
- else
- error("unrecognized pragma(%s)", ident->toChars());
-
-Ldecl:
- if (decl)
- {
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < decl->length; i++)
- {
- Dsymbol *s = (*decl)[i];
-
- s->semantic(sc2);
-
- if (ident == Id::mangle)
- {
- assert(args && args->length == 1);
- if (StringExp *se = (*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)
- error("can only apply to a single declaration");
- }
- }
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
- return;
-
-Lnodecl:
- if (decl)
- {
- error("pragma is missing closing ';'");
- goto Ldecl; // do them anyway, to avoid segfaults.
- }
-}
-
const char *PragmaDeclaration::kind() const
{
return "pragma";
Dsymbol::setScope(sc);
}
-void StaticIfDeclaration::semantic(Scope *sc)
-{
- AttribDeclaration::semantic(sc);
-}
-
const char *StaticIfDeclaration::kind() const
{
return "static if";
// do not evaluate aggregate before semantic pass
}
-void StaticForeachDeclaration::semantic(Scope *sc)
-{
- AttribDeclaration::semantic(sc);
-}
-
const char *StaticForeachDeclaration::kind() const
{
return "static foreach";
Dsymbol::setScope(sc);
}
-void CompileDeclaration::compileIt(Scope *sc)
-{
- //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars());
- StringExp *se = semanticString(sc, exp, "argument to mixin");
- if (!se)
- return;
- se = se->toUTF8(sc);
-
- unsigned errors = global.errors;
- Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
- p.nextToken();
-
- decl = p.parseDeclDefs(0);
- if (p.token.value != TOKeof)
- exp->error("incomplete mixin declaration (%s)", se->toChars());
- if (p.errors)
- {
- assert(global.errors != errors);
- decl = NULL;
- }
-}
-
-void CompileDeclaration::semantic(Scope *sc)
-{
- //printf("CompileDeclaration::semantic()\n");
-
- if (!compiled)
- {
- compileIt(sc);
- AttribDeclaration::addMember(sc, scopesym);
- compiled = true;
-
- if (_scope && decl)
- {
- for (size_t i = 0; i < decl->length; i++)
- {
- Dsymbol *s = (*decl)[i];
- s->setScope(_scope);
- }
- }
- }
- AttribDeclaration::semantic(sc);
-}
-
const char *CompileDeclaration::kind() const
{
return "mixin";
return AttribDeclaration::setScope(sc);
}
-void UserAttributeDeclaration::semantic(Scope *sc)
-{
- //printf("UserAttributeDeclaration::semantic() %p\n", this);
- if (decl && !_scope)
- Dsymbol::setScope(sc); // for function local symbols
-
- return AttribDeclaration::semantic(sc);
-}
-
-static void udaExpressionEval(Scope *sc, Expressions *exps)
+void udaExpressionEval(Scope *sc, Expressions *exps)
{
for (size_t i = 0; i < exps->length; i++)
{
Expression *e = (*exps)[i];
if (e)
{
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (definitelyValueParameter(e))
e = e->ctfeInterpret();
if (e->op == TOKtuple)
}
}
-void UserAttributeDeclaration::semantic2(Scope *sc)
-{
- if (decl && atts && atts->length && _scope)
- {
- _scope = NULL;
- udaExpressionEval(sc, atts);
- }
-
- AttribDeclaration::semantic2(sc);
-}
-
Expressions *UserAttributeDeclaration::concat(Expressions *udas1, Expressions *udas2)
{
Expressions *udas;
/* 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.
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
void importAll(Scope *sc);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
- void semantic3(Scope *sc);
void addComment(const utf8_t *comment);
const char *kind() const;
bool oneMember(Dsymbol **ps, Identifier *ident);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
void setScope(Scope *sc);
- void semantic2(Scope *sc);
const char *getMessage();
void accept(Visitor *v) { v->visit(this); }
};
AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
- void semantic2(Scope *sc);
structalign_t getAlignment(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
void setScope(Scope *sc);
- void semantic(Scope *sc);
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
const char *kind() const;
AnonDeclaration *isAnonDeclaration() { return this; }
PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
- void semantic(Scope *sc);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
};
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
void importAll(Scope *sc);
- void semantic(Scope *sc);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
};
void addComment(const utf8_t *comment);
void setScope(Scope *sc);
void importAll(Scope *sc);
- void semantic(Scope *sc);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
};
Dsymbol *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
- void compileIt(Scope *sc);
- void semantic(Scope *sc);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
};
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
void setScope(Scope *sc);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
static Expressions *concat(Expressions *udas1, Expressions *udas2);
Expressions *getAttributes();
const char *kind() const;
/* 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.
void visit(CompoundAsmStatement *s)
{
if (mustNotThrow && !(s->stc & STCnothrow))
- s->deprecation("asm statement is assumed to throw - mark it with 'nothrow' if it does not");
+ s->deprecation("asm statement is assumed to throw - mark it with `nothrow` if it does not");
// Assume the worst
result = BEfallthru | BEreturn | BEgoto | BEhalt;
/* 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.
{
if (ce->f)
{
- ce->error("%s '%s' is not nothrow",
+ ce->error("%s `%s` is not nothrow",
ce->f->kind(), ce->f->toPrettyChars());
}
else
Expression *e1 = ce->e1;
if (e1->op == TOKstar) // print 'fp' if e1 is (*fp)
e1 = ((PtrExp *)e1)->e1;
- ce->error("'%s' is not nothrow", e1->toChars());
+ ce->error("`%s` is not nothrow", e1->toChars());
}
}
stop = true;
{
if (mustNotThrow)
{
- ne->error("%s '%s' is not nothrow",
+ ne->error("%s `%s` is not nothrow",
ne->allocator->kind(), ne->allocator->toPrettyChars());
}
stop = true;
{
if (mustNotThrow)
{
- ne->error("%s '%s' is not nothrow",
+ ne->error("%s `%s` is not nothrow",
ne->member->kind(), ne->member->toPrettyChars());
}
stop = true;
{
if (mustNotThrow)
{
- de->error("%s '%s' is not nothrow",
+ de->error("%s `%s` is not nothrow",
ad->dtor->kind(), ad->dtor->toPrettyChars());
}
stop = true;
{
if (mustNotThrow)
{
- de->error("%s '%s' is not nothrow",
+ de->error("%s `%s` is not nothrow",
ad->aggDelete->kind(), ad->aggDelete->toPrettyChars());
}
stop = true;
{
if (mustNotThrow)
{
- ae->error("%s '%s' is not nothrow",
+ ae->error("%s `%s` is not nothrow",
sd->postblit->kind(), sd->postblit->toPrettyChars());
}
stop = true;
/* 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.
#include "template.h"
#include "tokens.h"
-Expression *semantic(Expression *e, Scope *sc);
-
/*******************************************
* Merge function attributes pure, nothrow, @safe, @nogc, and @disable
*/
sc2->stc = 0;
sc2->linkage = LINKd;
- fop->semantic(sc2);
- fop->semantic2(sc2);
+ dsymbolSemantic(fop, sc2);
+ semantic2(fop, sc2);
// Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.
sc2->pop();
parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL));
tfeqptr = new TypeFunction(ParameterList(parameters), Type::tbool, LINKd);
tfeqptr->mod = MODconst;
- tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx);
+ tfeqptr = (TypeFunction *)typeSemantic(tfeqptr, Loc(), &scx);
}
fd = fd->overloadExactMatch(tfeqptr);
if (fd)
Expression *e = new IdentifierExp(sd->loc, Id::empty);
e = new DotIdExp(sd->loc, e, Id::object);
e = new DotIdExp(sd->loc, e, id);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
Dsymbol *s = getDsymbol(e);
assert(s);
sd->xerreq = s->isFuncDeclaration();
sc2->stc = 0;
sc2->linkage = LINKd;
- fop->semantic(sc2);
- fop->semantic2(sc2);
+ dsymbolSemantic(fop, sc2);
+ semantic2(fop, sc2);
sc2->pop();
if (global.endGagging(errors)) // if errors happened
parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL));
tfcmpptr = new TypeFunction(ParameterList(parameters), Type::tint32, LINKd);
tfcmpptr->mod = MODconst;
- tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx);
+ tfcmpptr = (TypeFunction *)typeSemantic(tfcmpptr, Loc(), &scx);
}
fd = fd->overloadExactMatch(tfcmpptr);
if (fd)
Expression *e = new IdentifierExp(sd->loc, Id::empty);
e = new DotIdExp(sd->loc, e, Id::object);
e = new DotIdExp(sd->loc, e, id);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
Dsymbol *s = getDsymbol(e);
assert(s);
sd->xerrcmp = s->isFuncDeclaration();
sc2->stc = 0;
sc2->linkage = LINKd;
- fop->semantic(sc2);
- fop->semantic2(sc2);
+ dsymbolSemantic(fop, sc2);
+ semantic2(fop, sc2);
sc2->pop();
if (global.endGagging(errors)) // if errors happened
sc2->stc = 0;
sc2->linkage = LINKd;
- fop->semantic(sc2);
- fop->semantic2(sc2);
+ dsymbolSemantic(fop, sc2);
+ semantic2(fop, sc2);
sc2->pop();
dd->fbody = (stc & STCdisable) ? NULL : new CompoundStatement(loc, a);
sd->postblits.shift(dd);
sd->members->push(dd);
- dd->semantic(sc);
+ dsymbolSemantic(dd, sc);
}
FuncDeclaration *xpostblit = NULL;
dd->storage_class |= STCinference;
dd->fbody = new ExpStatement(loc, e);
sd->members->push(dd);
- dd->semantic(sc);
+ dsymbolSemantic(dd, sc);
xpostblit = dd;
break;
}
if (xpostblit)
{
AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit);
- alias->semantic(sc);
+ dsymbolSemantic(alias, sc);
sd->members->push(alias);
alias->addMember(sc, sd); // add to symbol table
}
dd->fbody = new ExpStatement(loc, e);
ad->dtors.shift(dd);
ad->members->push(dd);
- dd->semantic(sc);
+ dsymbolSemantic(dd, sc);
}
FuncDeclaration *xdtor = NULL;
dd->storage_class |= STCinference;
dd->fbody = new ExpStatement(loc, e);
ad->members->push(dd);
- dd->semantic(sc);
+ dsymbolSemantic(dd, sc);
xdtor = dd;
break;
}
if (xdtor)
{
AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor);
- alias->semantic(sc);
+ dsymbolSemantic(alias, sc);
ad->members->push(alias);
alias->addMember(sc, ad); // add to symbol table
}
inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id::classInvariant);
inv->fbody = new ExpStatement(loc, e);
ad->members->push(inv);
- inv->semantic(sc);
+ dsymbolSemantic(inv, sc);
return inv;
}
}
/* 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.
/* 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.
/* 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.
#include "arraytypes.h"
#include "tokens.h"
-Expression *semantic(Expression *e, Scope *sc);
bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
int findCondition(Identifiers *ids, Identifier *ident)
Expression *aggr = sfe->aggrfe->aggr;
Expression *el = new ArrayLengthExp(aggr->loc, aggr);
sc = sc->startCTFE();
- el = semantic(el, sc);
+ el = expressionSemantic(el, sc);
sc = sc->endCTFE();
el = el->optimize(WANTvalue);
el = el->ctfeInterpret();
}
}
sfe->aggrfe->aggr = new TupleExp(aggr->loc, es);
- sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc);
+ sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc);
sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
}
else
if (sfe->rangefe)
{
sc = sc->startCTFE();
- sfe->rangefe->lwr = semantic(sfe->rangefe->lwr, sc);
+ sfe->rangefe->lwr = expressionSemantic(sfe->rangefe->lwr, sc);
sfe->rangefe->lwr = resolveProperties(sc, sfe->rangefe->lwr);
- sfe->rangefe->upr = semantic(sfe->rangefe->upr, sc);
+ sfe->rangefe->upr = expressionSemantic(sfe->rangefe->upr, sc);
sfe->rangefe->upr = resolveProperties(sc, sfe->rangefe->upr);
sc = sc->endCTFE();
sfe->rangefe->lwr = sfe->rangefe->lwr->optimize(WANTvalue);
Expression *aggr;
Type *indexty;
- if (sfe->rangefe && (indexty = ety->semantic(aloc, sc))->isintegral())
+ if (sfe->rangefe && (indexty = typeSemantic(ety, aloc, sc))->isintegral())
{
sfe->rangefe->lwr->type = indexty;
sfe->rangefe->upr->type = indexty;
{
aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
sc = sc->startCTFE();
- aggr = semantic(aggr, sc);
+ aggr = expressionSemantic(aggr, sc);
aggr = resolveProperties(sc, aggr);
sc = sc->endCTFE();
aggr = aggr->optimize(WANTvalue);
if (sfe->aggrfe)
{
sc = sc->startCTFE();
- sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc);
+ sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc);
sc = sc->endCTFE();
sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
Type *tab = sfe->aggrfe->aggr->type->toBasetype();
void checkReserved(Loc loc, const char *ident)
{
if (isReserved(ident))
- error(loc, "version identifier '%s' is reserved and cannot be set", ident);
+ error(loc, "version identifier `%s` is reserved and cannot be set", ident);
}
void VersionCondition::addGlobalIdent(const char *ident)
/* 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.
/* 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.
/* 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.
/* 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.
/* 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.
/* 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.
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
bool isCommutative(TOK op);
MOD MODmerge(MOD mod1, MOD mod2);
-Expression *semantic(Expression *e, Scope *sc);
/* ==================== implicitCast ====================== */
TypeVector *tv = (TypeVector *)tob;
result = new CastExp(e->loc, e, tv->elementType());
result = new VectorExp(e->loc, result, tob);
- result = ::semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
else if (tob->ty != Tvector && t1b->ty == Tvector)
{
f->tookAddressOf++;
SymOffExp *se = new SymOffExp(e->loc, f, 0, false);
- ::semantic(se, sc);
+ expressionSemantic(se, sc);
// Let SymOffExp::castTo() do the heavy lifting
visit(se);
return;
(*ae->elements)[i] = ex;
}
Expression *ev = new VectorExp(e->loc, ae, tb);
- ev = ::semantic(ev, sc);
+ ev = expressionSemantic(ev, sc);
result = ev;
return;
}
if (f->needThis() && hasThis(sc))
{
result = new DelegateExp(e->loc, new ThisExp(e->loc), f, false);
- result = ::semantic(result, sc);
+ result = expressionSemantic(result, sc);
}
else if (f->isNested())
{
result = new DelegateExp(e->loc, new IntegerExp(0), f, false);
- result = ::semantic(result, sc);
+ result = expressionSemantic(result, sc);
}
else if (f->needThis())
{
- e->error("no 'this' to create delegate for %s", f->toChars());
+ e->error("no `this` to create delegate for %s", f->toChars());
result = new ErrorExp();
return;
}
else
tx = d->pointerTo();
- tx = tx->semantic(e1->loc, sc);
+ tx = typeSemantic(tx, e1->loc, sc);
if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx))
{
/* 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.
return sc2;
}
-/* 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 = type->semantic(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;
- sym->semantic(NULL);
- cd->_scope = NULL;
-}
-
-static void badObjectDotD(ClassDeclaration *cd)
-{
- cd->error("missing or corrupt object.d");
- fatal();
-}
-
-void ClassDeclaration::semantic(Scope *sc)
-{
- //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
- //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
- //printf("sc->stc = %x\n", sc->stc);
-
- //{ static int n; if (++n == 20) *(char*)0=0; }
-
- if (semanticRun >= PASSsemanticdone)
- return;
- unsigned errors = global.errors;
-
- //printf("+ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
-
- Scope *scx = NULL;
- if (_scope)
- {
- sc = _scope;
- scx = _scope; // save so we don't make redundant copies
- _scope = NULL;
- }
-
- if (!parent)
- {
- assert(sc->parent);
- parent = sc->parent;
- }
-
- if (this->errors)
- type = Type::terror;
- type = type->semantic(loc, sc);
-
- if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
- {
- TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
- if (ti && isError(ti))
- ((TypeClass *)type)->sym = this;
- }
-
- // Ungag errors when not speculative
- Ungag ungag = ungagSpeculative();
-
- if (semanticRun == PASSinit)
- {
- protection = sc->protection;
-
- storage_class |= sc->stc;
- if (storage_class & STCdeprecated)
- isdeprecated = true;
- if (storage_class & STCauto)
- error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?");
- if (storage_class & STCscope)
- isscope = true;
- if (storage_class & STCabstract)
- isabstract = ABSyes;
-
- userAttribDecl = sc->userAttribDecl;
-
- if (sc->linkage == LINKcpp)
- classKind = ClassKind::cpp;
- if (sc->linkage == LINKobjc)
- objc()->setObjc(this);
- }
- else if (symtab && !scx)
- {
- return;
- }
- semanticRun = PASSsemantic;
-
- if (baseok < BASEOKdone)
- {
- baseok = BASEOKin;
-
- // Expand any tuples in baseclasses[]
- for (size_t i = 0; i < baseclasses->length; )
- {
- BaseClass *b = (*baseclasses)[i];
- b->type = resolveBase(this, sc, scx, b->type);
-
- Type *tb = b->type->toBasetype();
- if (tb->ty == Ttuple)
- {
- TypeTuple *tup = (TypeTuple *)tb;
- baseclasses->remove(i);
- size_t dim = Parameter::dim(tup->arguments);
- for (size_t j = 0; j < dim; j++)
- {
- Parameter *arg = Parameter::getNth(tup->arguments, j);
- b = new BaseClass(arg->type);
- baseclasses->insert(i + j, b);
- }
- }
- else
- i++;
- }
-
- if (baseok >= BASEOKdone)
- {
- //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
- if (semanticRun >= PASSsemanticdone)
- return;
- goto Lancestorsdone;
- }
-
- // See if there's a base class as first in baseclasses[]
- if (baseclasses->length)
- {
- BaseClass *b = (*baseclasses)[0];
- Type *tb = b->type->toBasetype();
- TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
- if (!tc)
- {
- if (b->type != Type::terror)
- error("base type must be class or interface, not %s", b->type->toChars());
- baseclasses->remove(0);
- goto L7;
- }
-
- if (tc->sym->isDeprecated())
- {
- if (!isDeprecated())
- {
- // Deriving from deprecated class makes this one deprecated too
- isdeprecated = true;
-
- tc->checkDeprecated(loc, sc);
- }
- }
-
- if (tc->sym->isInterfaceDeclaration())
- goto L7;
-
- for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
- {
- if (cdb == this)
- {
- error("circular inheritance");
- baseclasses->remove(0);
- goto L7;
- }
- }
-
- /* Bugzilla 11034: Essentially, class inheritance hierarchy
- * and instance size of each classes are orthogonal information.
- * Therefore, even if tc->sym->sizeof == SIZEOKnone,
- * we need to set baseClass field for class covariance check.
- */
- baseClass = tc->sym;
- b->sym = baseClass;
-
- if (tc->sym->baseok < BASEOKdone)
- resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
- if (tc->sym->baseok < BASEOKdone)
- {
- //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
- if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
- baseok = BASEOKnone;
- }
- L7: ;
- }
-
- // Treat the remaining entries in baseclasses as interfaces
- // Check for errors, handle forward references
- for (size_t i = (baseClass ? 1 : 0); i < baseclasses->length; )
- {
- BaseClass *b = (*baseclasses)[i];
- Type *tb = b->type->toBasetype();
- TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
- if (!tc || !tc->sym->isInterfaceDeclaration())
- {
- if (b->type != Type::terror)
- error("base type must be interface, not %s", b->type->toChars());
- baseclasses->remove(i);
- continue;
- }
-
- // Check for duplicate interfaces
- for (size_t j = (baseClass ? 1 : 0); j < i; j++)
- {
- BaseClass *b2 = (*baseclasses)[j];
- if (b2->sym == tc->sym)
- {
- error("inherits from duplicate interface %s", b2->sym->toChars());
- baseclasses->remove(i);
- continue;
- }
- }
-
- if (tc->sym->isDeprecated())
- {
- if (!isDeprecated())
- {
- // Deriving from deprecated class makes this one deprecated too
- isdeprecated = true;
-
- tc->checkDeprecated(loc, sc);
- }
- }
-
- b->sym = tc->sym;
-
- if (tc->sym->baseok < BASEOKdone)
- resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
- if (tc->sym->baseok < BASEOKdone)
- {
- //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
- if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
- baseok = BASEOKnone;
- }
- i++;
- }
- if (baseok == BASEOKnone)
- {
- // Forward referencee of one or more bases, try again later
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- _scope->_module->addDeferredSemantic(this);
- //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
- return;
- }
- baseok = BASEOKdone;
-
- // If no base class, and this is not an Object, use Object as base class
- if (!baseClass && ident != Id::Object && !isCPPclass())
- {
- if (!object || object->errors)
- badObjectDotD(this);
-
- Type *t = object->type;
- t = t->semantic(loc, sc)->toBasetype();
- if (t->ty == Terror)
- badObjectDotD(this);
- assert(t->ty == Tclass);
- TypeClass *tc = (TypeClass *)t;
-
- BaseClass *b = new BaseClass(tc);
- baseclasses->shift(b);
-
- baseClass = tc->sym;
- assert(!baseClass->isInterfaceDeclaration());
- b->sym = baseClass;
- }
- if (baseClass)
- {
- if (baseClass->storage_class & STCfinal)
- error("cannot inherit from final class %s", baseClass->toChars());
-
- // Inherit properties from base class
- if (baseClass->isCOMclass())
- com = true;
- if (baseClass->isCPPclass())
- classKind = ClassKind::cpp;
- if (baseClass->isscope)
- isscope = true;
- enclosing = baseClass->enclosing;
- storage_class |= baseClass->storage_class & STC_TYPECTOR;
- }
-
- interfaces.length = baseclasses->length - (baseClass ? 1 : 0);
- interfaces.ptr = baseclasses->tdata() + (baseClass ? 1 : 0);
-
- for (size_t i = 0; i < interfaces.length; i++)
- {
- BaseClass *b = interfaces.ptr[i];
- // If this is an interface, and it derives from a COM interface,
- // then this is a COM interface too.
- if (b->sym->isCOMinterface())
- com = true;
- if (isCPPclass() && !b->sym->isCPPinterface())
- {
- ::error(loc, "C++ class '%s' cannot implement D interface '%s'",
- toPrettyChars(), b->sym->toPrettyChars());
- }
- }
-
- interfaceSemantic(sc);
- }
-Lancestorsdone:
- //printf("\tClassDeclaration::semantic(%s) baseok = %d\n", toChars(), baseok);
-
- if (!members) // if opaque declaration
- {
- semanticRun = PASSsemanticdone;
- return;
- }
- if (!symtab)
- {
- symtab = new DsymbolTable();
-
- /* Bugzilla 12152: The semantic analysis of base classes should be finished
- * before the members semantic analysis of this class, in order to determine
- * vtbl in this class. However if a base class refers the member of this class,
- * it can be resolved as a normal forward reference.
- * Call addMember() and setScope() to make this class members visible from the base classes.
- */
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->addMember(sc, this);
- }
-
- Scope *sc2 = newScope(sc);
-
- /* Set scope so if there are forward references, we still might be able to
- * resolve individual members like enums.
- */
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("[%d] setScope %s %s, sc2 = %p\n", i, s->kind(), s->toChars(), sc2);
- s->setScope(sc2);
- }
-
- sc2->pop();
- }
-
- for (size_t i = 0; i < baseclasses->length; i++)
- {
- BaseClass *b = (*baseclasses)[i];
- Type *tb = b->type->toBasetype();
- assert(tb->ty == Tclass);
- TypeClass *tc = (TypeClass *)tb;
-
- if (tc->sym->semanticRun < PASSsemanticdone)
- {
- // Forward referencee of one or more bases, try again later
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
- _scope->_module->addDeferredSemantic(this);
- //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
- return;
- }
- }
-
- if (baseok == BASEOKdone)
- {
- baseok = BASEOKsemanticdone;
-
- // initialize vtbl
- if (baseClass)
- {
- if (isCPPclass() && baseClass->vtbl.length == 0)
- {
- error("C++ base class %s needs at least one virtual function", baseClass->toChars());
- }
-
- // Copy vtbl[] from base class
- vtbl.setDim(baseClass->vtbl.length);
- memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.length);
-
- vthis = baseClass->vthis;
- }
- else
- {
- // No base class, so this is the root of the class hierarchy
- vtbl.setDim(0);
- if (vtblOffset())
- vtbl.push(this); // leave room for classinfo as first member
- }
-
- /* If this is a nested class, add the hidden 'this'
- * member which is a pointer to the enclosing scope.
- */
- if (vthis) // if inheriting from nested class
- {
- // Use the base class's 'this' member
- if (storage_class & STCstatic)
- error("static class cannot inherit from nested class %s", baseClass->toChars());
- if (toParent2() != baseClass->toParent2() &&
- (!toParent2() ||
- !baseClass->toParent2()->getType() ||
- !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL)))
- {
- if (toParent2())
- {
- error("is nested within %s, but super class %s is nested within %s",
- toParent2()->toChars(),
- baseClass->toChars(),
- baseClass->toParent2()->toChars());
- }
- else
- {
- error("is not nested, but super class %s is nested within %s",
- baseClass->toChars(),
- baseClass->toParent2()->toChars());
- }
- enclosing = NULL;
- }
- }
- else
- makeNested();
- }
-
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->importAll(sc2);
- }
-
- // Note that members.length can grow due to tuple expansion during semantic()
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic(sc2);
- }
-
- if (!determineFields())
- {
- assert(type == Type::terror);
- sc2->pop();
- return;
- }
-
- /* Following special member functions creation needs semantic analysis
- * completion of sub-structs in each field types.
- */
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *v = fields[i];
- Type *tb = v->type->baseElemOf();
- if (tb->ty != Tstruct)
- continue;
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- if (sd->semanticRun >= PASSsemanticdone)
- continue;
-
- sc2->pop();
-
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- _scope->_module->addDeferredSemantic(this);
- //printf("\tdeferring %s\n", toChars());
- return;
- }
-
- /* Look for special member functions.
- * They must be in this class, not in a base class.
- */
-
- // Can be in base class
- aggNew = (NewDeclaration *)search(Loc(), Id::classNew);
- aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);
-
- // Look for the constructor
- ctor = searchCtor();
-
- if (!ctor && noDefaultCtor)
- {
- // A class object is always created by constructor, so this check is legitimate.
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *v = fields[i];
- if (v->storage_class & STCnodefaultctor)
- ::error(v->loc, "field %s must be initialized in constructor", v->toChars());
- }
- }
-
- // If this class has no constructor, but base class has a default
- // ctor, create a constructor:
- // this() { }
- if (!ctor && baseClass && baseClass->ctor)
- {
- FuncDeclaration *fd = resolveFuncCall(loc, sc2, baseClass->ctor, NULL, type, NULL, 1);
- if (!fd) // try shared base ctor instead
- fd = resolveFuncCall(loc, sc2, baseClass->ctor, NULL, type->sharedOf(), NULL, 1);
- if (fd && !fd->errors)
- {
- //printf("Creating default this(){} for class %s\n", toChars());
- TypeFunction *btf = fd->type->toTypeFunction();
- TypeFunction *tf = new TypeFunction(ParameterList(), NULL, LINKd, fd->storage_class);
- tf->mod = btf->mod;
- tf->purity = btf->purity;
- tf->isnothrow = btf->isnothrow;
- tf->isnogc = btf->isnogc;
- tf->trust = btf->trust;
-
- CtorDeclaration *ctor = new CtorDeclaration(loc, Loc(), 0, tf);
- ctor->fbody = new CompoundStatement(Loc(), new Statements());
-
- members->push(ctor);
- ctor->addMember(sc, this);
- ctor->semantic(sc2);
-
- this->ctor = ctor;
- defaultCtor = ctor;
- }
- else
- {
- error("cannot implicitly generate a default ctor when base class %s is missing a default ctor",
- baseClass->toPrettyChars());
- }
- }
-
- dtor = buildDtor(this, sc2);
-
- if (FuncDeclaration *f = hasIdentityOpAssign(this, sc2))
- {
- if (!(f->storage_class & STCdisable))
- error(f->loc, "identity assignment operator overload is illegal");
- }
-
- inv = buildInv(this, sc2);
-
- Module::dprogress++;
- semanticRun = PASSsemanticdone;
- //printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type);
- //members.print();
-
- sc2->pop();
-
- if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
- {
- // https://issues.dlang.org/show_bug.cgi?id=17492
- ClassDeclaration *cd = ((TypeClass *)type)->sym;
- error("already exists at %s. Perhaps in another function with the same name?", cd->loc.toChars());
- }
-
- if (global.errors != errors)
- {
- // The type is no good.
- type = Type::terror;
- this->errors = true;
- if (deferred)
- deferred->errors = true;
- }
-
- // Verify fields of a synchronized class are not public
- if (storage_class & STCsynchronized)
- {
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *vd = fields[i];
- if (!vd->isThisDeclaration() &&
- !vd->prot().isMoreRestrictiveThan(Prot(Prot::public_)))
- {
- vd->error("Field members of a synchronized class cannot be %s",
- protectionToChars(vd->prot().kind));
- }
- }
- }
-
- if (deferred && !global.gag)
- {
- deferred->semantic2(sc);
- deferred->semantic3(sc);
- }
- //printf("-ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
-}
-
/*********************************************
* Determine if 'this' is a base class of cd.
* This is used to detect circular inheritance only.
*/
if (!cd->baseClass && cd->semanticRun < PASSsemanticdone && !cd->isInterfaceDeclaration())
{
- cd->semantic(NULL);
+ dsymbolSemantic(cd, NULL);
if (!cd->baseClass && cd->semanticRun < PASSsemanticdone)
cd->error("base class is forward referenced by %s", toChars());
}
{
// must semantic on base class/interfaces
++inuse;
- semantic(NULL);
+ dsymbolSemantic(this, NULL);
--inuse;
}
}
if (!members || !symtab) // opaque or addMember is not yet done
{
- error("is forward referenced when looking for '%s'", ident->toChars());
+ error("is forward referenced when looking for `%s`", ident->toChars());
//*(char*)0=0;
return NULL;
}
return fdmatch;
}
-void ClassDeclaration::interfaceSemantic(Scope *)
-{
- vtblInterfaces = new BaseClasses();
- vtblInterfaces->reserve(interfaces.length);
-
- for (size_t i = 0; i < interfaces.length; i++)
- {
- BaseClass *b = interfaces.ptr[i];
- vtblInterfaces->push(b);
- b->copyBaseInterfaces(vtblInterfaces);
- }
-}
-
/****************************************
*/
return 0;
if (fd->_scope)
- fd->semantic(NULL);
+ dsymbolSemantic(fd, NULL);
if (fd->isAbstract())
return 1;
return sc2;
}
-void InterfaceDeclaration::semantic(Scope *sc)
-{
- //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
- if (semanticRun >= PASSsemanticdone)
- return;
- unsigned errors = global.errors;
-
- //printf("+InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);
-
- Scope *scx = NULL;
- if (_scope)
- {
- sc = _scope;
- scx = _scope; // save so we don't make redundant copies
- _scope = NULL;
- }
-
- if (!parent)
- {
- assert(sc->parent && sc->func);
- parent = sc->parent;
- }
- assert(parent && !isAnonymous());
-
- if (this->errors)
- type = Type::terror;
- type = type->semantic(loc, sc);
-
- if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
- {
- TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
- if (ti && isError(ti))
- ((TypeClass *)type)->sym = this;
- }
-
- // Ungag errors when not speculative
- Ungag ungag = ungagSpeculative();
-
- if (semanticRun == PASSinit)
- {
- protection = sc->protection;
-
- storage_class |= sc->stc;
- if (storage_class & STCdeprecated)
- isdeprecated = true;
-
- userAttribDecl = sc->userAttribDecl;
- }
- else if (symtab)
- {
- if (sizeok == SIZEOKdone || !scx)
- {
- semanticRun = PASSsemanticdone;
- return;
- }
- }
- semanticRun = PASSsemantic;
-
- if (baseok < BASEOKdone)
- {
- baseok = BASEOKin;
-
- // Expand any tuples in baseclasses[]
- for (size_t i = 0; i < baseclasses->length; )
- {
- BaseClass *b = (*baseclasses)[i];
- b->type = resolveBase(this, sc, scx, b->type);
-
- Type *tb = b->type->toBasetype();
- if (tb->ty == Ttuple)
- {
- TypeTuple *tup = (TypeTuple *)tb;
- baseclasses->remove(i);
- size_t dim = Parameter::dim(tup->arguments);
- for (size_t j = 0; j < dim; j++)
- {
- Parameter *arg = Parameter::getNth(tup->arguments, j);
- b = new BaseClass(arg->type);
- baseclasses->insert(i + j, b);
- }
- }
- else
- i++;
- }
-
- if (baseok >= BASEOKdone)
- {
- //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
- if (semanticRun >= PASSsemanticdone)
- return;
- goto Lancestorsdone;
- }
-
- if (!baseclasses->length && sc->linkage == LINKcpp)
- classKind = ClassKind::cpp;
- if (sc->linkage == LINKobjc)
- objc()->setObjc(this);
-
- // Check for errors, handle forward references
- for (size_t i = 0; i < baseclasses->length; )
- {
- BaseClass *b = (*baseclasses)[i];
- Type *tb = b->type->toBasetype();
- TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
- if (!tc || !tc->sym->isInterfaceDeclaration())
- {
- if (b->type != Type::terror)
- error("base type must be interface, not %s", b->type->toChars());
- baseclasses->remove(i);
- continue;
- }
-
- // Check for duplicate interfaces
- for (size_t j = 0; j < i; j++)
- {
- BaseClass *b2 = (*baseclasses)[j];
- if (b2->sym == tc->sym)
- {
- error("inherits from duplicate interface %s", b2->sym->toChars());
- baseclasses->remove(i);
- continue;
- }
- }
-
- if (tc->sym == this || isBaseOf2(tc->sym))
- {
- error("circular inheritance of interface");
- baseclasses->remove(i);
- continue;
- }
-
- if (tc->sym->isDeprecated())
- {
- if (!isDeprecated())
- {
- // Deriving from deprecated class makes this one deprecated too
- isdeprecated = true;
-
- tc->checkDeprecated(loc, sc);
- }
- }
-
- b->sym = tc->sym;
-
- if (tc->sym->baseok < BASEOKdone)
- resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
- if (tc->sym->baseok < BASEOKdone)
- {
- //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
- if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
- baseok = BASEOKnone;
- }
- i++;
- }
- if (baseok == BASEOKnone)
- {
- // Forward referencee of one or more bases, try again later
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- _scope->_module->addDeferredSemantic(this);
- return;
- }
- baseok = BASEOKdone;
-
- interfaces.length = baseclasses->length;
- interfaces.ptr = baseclasses->tdata();
-
- for (size_t i = 0; i < interfaces.length; i++)
- {
- BaseClass *b = interfaces.ptr[i];
- // If this is an interface, and it derives from a COM interface,
- // then this is a COM interface too.
- if (b->sym->isCOMinterface())
- com = true;
- if (b->sym->isCPPinterface())
- classKind = ClassKind::cpp;
- }
-
- interfaceSemantic(sc);
- }
-Lancestorsdone:
-
- if (!members) // if opaque declaration
- {
- semanticRun = PASSsemanticdone;
- return;
- }
- if (!symtab)
- symtab = new DsymbolTable();
-
- for (size_t i = 0; i < baseclasses->length; i++)
- {
- BaseClass *b = (*baseclasses)[i];
- Type *tb = b->type->toBasetype();
- assert(tb->ty == Tclass);
- TypeClass *tc = (TypeClass *)tb;
-
- if (tc->sym->semanticRun < PASSsemanticdone)
- {
- // Forward referencee of one or more bases, try again later
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- if (tc->sym->_scope)
- tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
- _scope->_module->addDeferredSemantic(this);
- return;
- }
- }
-
- if (baseok == BASEOKdone)
- {
- baseok = BASEOKsemanticdone;
-
- // initialize vtbl
- if (vtblOffset())
- vtbl.push(this); // leave room at vtbl[0] for classinfo
-
- // Cat together the vtbl[]'s from base interfaces
- for (size_t i = 0; i < interfaces.length; i++)
- {
- BaseClass *b = interfaces.ptr[i];
-
- // Skip if b has already appeared
- for (size_t k = 0; k < i; k++)
- {
- if (b == interfaces.ptr[k])
- goto Lcontinue;
- }
-
- // Copy vtbl[] from base class
- if (b->sym->vtblOffset())
- {
- size_t d = b->sym->vtbl.length;
- if (d > 1)
- {
- vtbl.reserve(d - 1);
- for (size_t j = 1; j < d; j++)
- vtbl.push(b->sym->vtbl[j]);
- }
- }
- else
- {
- vtbl.append(&b->sym->vtbl);
- }
-
- Lcontinue:
- ;
- }
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->addMember(sc, this);
- }
-
- Scope *sc2 = newScope(sc);
-
- /* Set scope so if there are forward references, we still might be able to
- * resolve individual members like enums.
- */
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("setScope %s %s\n", s->kind(), s->toChars());
- s->setScope(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->importAll(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic(sc2);
- }
-
- Module::dprogress++;
- semanticRun = PASSsemanticdone;
- //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);
- //members->print();
-
- sc2->pop();
-
- if (global.errors != errors)
- {
- // The type is no good.
- type = Type::terror;
- }
-
- assert(type->ty != Tclass || ((TypeClass *)type)->sym == this);
-}
-
/*******************************************
* Determine if 'this' is a base class of cd.
* (Actually, if it is an interface supported by cd)
//printf("newinstance = %d fd->toParent() = %s ifd->toParent() = %s\n",
//newinstance, fd->toParent()->toChars(), ifd->toParent()->toChars());
if (newinstance && fd->toParent() != cd && ifd->toParent() == sym)
- cd->error("interface function '%s' is not implemented", ifd->toFullSignature());
+ cd->error("interface function `%s` is not implemented", ifd->toFullSignature());
if (fd->toParent() == cd)
result = true;
//printf(" not found %p\n", fd);
// BUG: should mark this class as abstract?
if (!cd->isAbstract())
- cd->error("interface function '%s' is not implemented", ifd->toFullSignature());
+ cd->error("interface function `%s` is not implemented", ifd->toFullSignature());
fd = NULL;
}
/* 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.
#include "hdrgen.h"
bool checkNestedRef(Dsymbol *s, Dsymbol *p);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Expression *semantic(Expression *e, Scope *sc);
-Initializer *inferType(Initializer *init, Scope *sc);
-Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
/************************************
* Check to see the aggregate type is nested and its context pointer is
mangleOverride = NULL;
}
-void Declaration::semantic(Scope *)
-{
-}
-
const char *Declaration::kind() const
{
return "declaration";
if (scx->func == parent && (scx->flags & SCOPEcontract))
{
const char *s = isParameter() && parent->ident != Id::ensure ? "parameter" : "result";
- if (!flag) error(loc, "cannot modify %s '%s' in contract", s, toChars());
+ if (!flag) error(loc, "cannot modify %s `%s` in contract", s, toChars());
return 2; // do not report type related errors
}
}
tupletype = new TypeTuple(args);
if (hasdeco)
- return tupletype->semantic(Loc(), NULL);
+ return typeSemantic(tupletype, Loc(), NULL);
}
return tupletype;
return sa;
}
-void AliasDeclaration::semantic(Scope *sc)
-{
- if (semanticRun >= PASSsemanticdone)
- return;
- assert(semanticRun <= PASSsemantic);
-
- storage_class |= sc->stc & STCdeprecated;
- protection = sc->protection;
- userAttribDecl = sc->userAttribDecl;
-
- if (!sc->func && inNonRoot())
- return;
-
- aliasSemantic(sc);
-}
-
-void AliasDeclaration::aliasSemantic(Scope *sc)
-{
- //printf("AliasDeclaration::semantic() %s\n", toChars());
-
- // as AliasDeclaration::semantic, in case we're called first.
- // see https://issues.dlang.org/show_bug.cgi?id=21001
- storage_class |= sc->stc & STCdeprecated;
- protection = sc->protection;
- userAttribDecl = sc->userAttribDecl;
-
- // TypeTraits needs to know if it's located in an AliasDeclaration
- sc->flags |= SCOPEalias;
-
- if (aliassym)
- {
- FuncDeclaration *fd = aliassym->isFuncLiteralDeclaration();
- TemplateDeclaration *td = aliassym->isTemplateDeclaration();
- if (fd || (td && td->literal))
- {
- if (fd && fd->semanticRun >= PASSsemanticdone)
- {
- sc->flags &= ~SCOPEalias;
- return;
- }
-
- Expression *e = new FuncExp(loc, aliassym);
- e = ::semantic(e, sc);
- if (e->op == TOKfunction)
- {
- FuncExp *fe = (FuncExp *)e;
- aliassym = fe->td ? (Dsymbol *)fe->td : fe->fd;
- }
- else
- {
- aliassym = NULL;
- type = Type::terror;
- }
- sc->flags &= ~SCOPEalias;
- return;
- }
-
- if (aliassym->isTemplateInstance())
- aliassym->semantic(sc);
- sc->flags &= ~SCOPEalias;
- return;
- }
- inuse = 1;
-
- // Given:
- // alias foo.bar.abc def;
- // it is not knowable from the syntax whether this is an alias
- // for a type or an alias for a symbol. It is up to the semantic()
- // pass to distinguish.
- // If it is a type, then type is set and getType() will return that
- // type. If it is a symbol, then aliassym is set and type is NULL -
- // toAlias() will return aliasssym.
-
- unsigned int errors = global.errors;
- Type *oldtype = type;
-
- // Ungag errors when not instantiated DeclDefs scope alias
- Ungag ungag(global.gag);
- //printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated());
- if (parent && global.gag && !isInstantiated() && !toParent2()->isFuncDeclaration())
- {
- //printf("%s type = %s\n", toPrettyChars(), type->toChars());
- global.gag = 0;
- }
-
- /* This section is needed because Type::resolve() will:
- * const x = 3;
- * alias y = x;
- * try to convert identifier x to 3.
- */
- Dsymbol *s = type->toDsymbol(sc);
- if (errors != global.errors)
- {
- s = NULL;
- type = Type::terror;
- }
- if (s && s == this)
- {
- error("cannot resolve");
- s = NULL;
- type = Type::terror;
- }
- if (!s || !s->isEnumMember())
- {
- Type *t;
- Expression *e;
- Scope *sc2 = sc;
- if (storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCdisable))
- {
- // For 'ref' to be attached to function types, and picked
- // up by Type::resolve(), it has to go into sc.
- sc2 = sc->push();
- sc2->stc |= storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCshared | STCdisable);
- }
- type = type->addSTC(storage_class);
- type->resolve(loc, sc2, &e, &t, &s);
- if (sc2 != sc)
- sc2->pop();
-
- if (e) // Try to convert Expression to Dsymbol
- {
- s = getDsymbol(e);
- if (!s)
- {
- if (e->op != TOKerror)
- error("cannot alias an expression %s", e->toChars());
- t = Type::terror;
- }
- }
- type = t;
- }
- if (s == this)
- {
- assert(global.errors);
- type = Type::terror;
- s = NULL;
- }
- if (!s) // it's a type alias
- {
- //printf("alias %s resolved to type %s\n", toChars(), type->toChars());
- type = type->semantic(loc, sc);
- aliassym = NULL;
- }
- else // it's a symbolic alias
- {
- //printf("alias %s resolved to %s %s\n", toChars(), s->kind(), s->toChars());
- type = NULL;
- aliassym = s;
- }
- if (global.gag && errors != global.errors)
- {
- type = oldtype;
- aliassym = NULL;
- }
- inuse = 0;
- semanticRun = PASSsemanticdone;
-
- if (Dsymbol *sx = overnext)
- {
- overnext = NULL;
-
- if (!overloadInsert(sx))
- ScopeDsymbol::multiplyDefined(Loc(), sx, this);
- }
- sc->flags &= ~SCOPEalias;
-}
-
bool AliasDeclaration::overloadInsert(Dsymbol *s)
{
//printf("[%s] AliasDeclaration::overloadInsert('%s') s = %s %s @ [%s]\n",
}
else
{
- Type *t = type->semantic(loc, _scope);
+ Type *t = typeSemantic(type, loc, _scope);
if (t->ty == Terror)
goto Lerr;
if (global.errors != olderrors)
/* If this is an internal alias for selective/renamed import,
* load the module first.
*/
- _import->semantic(NULL);
+ dsymbolSemantic(_import, NULL);
}
if (_scope)
{
- aliasSemantic(_scope);
+ aliasSemantic(this, _scope);
}
}
return "overload alias"; // todo
}
-void OverDeclaration::semantic(Scope *)
-{
-}
-
bool OverDeclaration::equals(RootObject *o)
{
if (this == o)
return v;
}
-
-void VarDeclaration::semantic(Scope *sc)
-{
-// if (semanticRun > PASSinit)
-// return;
-// semanticRun = PASSsemantic;
-
- if (semanticRun >= PASSsemanticdone)
- return;
-
- Scope *scx = NULL;
- if (_scope)
- {
- sc = _scope;
- scx = sc;
- _scope = NULL;
- }
-
- if (!sc)
- return;
-
- semanticRun = PASSsemantic;
-
- /* Pick up storage classes from context, but except synchronized,
- * override, abstract, and final.
- */
- storage_class |= (sc->stc & ~(STCsynchronized | STCoverride | STCabstract | STCfinal));
- if (storage_class & STCextern && _init)
- error("extern symbols cannot have initializers");
-
- userAttribDecl = sc->userAttribDecl;
-
- AggregateDeclaration *ad = isThis();
- if (ad)
- storage_class |= ad->storage_class & STC_TYPECTOR;
-
- /* If auto type inference, do the inference
- */
- int inferred = 0;
- if (!type)
- {
- inuse++;
-
- // Infering the type requires running semantic,
- // so mark the scope as ctfe if required
- bool needctfe = (storage_class & (STCmanifest | STCstatic)) != 0;
- if (needctfe) sc = sc->startCTFE();
-
- //printf("inferring type for %s with init %s\n", toChars(), _init->toChars());
- _init = inferType(_init, sc);
- type = initializerToExpression(_init)->type;
-
- if (needctfe) sc = sc->endCTFE();
-
- inuse--;
- inferred = 1;
-
- /* This is a kludge to support the existing syntax for RAII
- * declarations.
- */
- storage_class &= ~STCauto;
- originalType = type->syntaxCopy();
- }
- else
- {
- if (!originalType)
- originalType = 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 |= (storage_class & STC_FUNCATTR);
- inuse++;
- type = type->semantic(loc, sc2);
- inuse--;
- sc2->pop();
- }
- //printf(" semantic type = %s\n", type ? type->toChars() : "null");
- if (type->ty == Terror)
- errors = true;
-
- type->checkDeprecated(loc, sc);
- linkage = sc->linkage;
- this->parent = sc->parent;
- //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars());
- protection = sc->protection;
-
- /* If scope's alignment is the default, use the type's alignment,
- * otherwise the scope overrrides.
- */
- alignment = sc->alignment();
- if (alignment == STRUCTALIGN_DEFAULT)
- alignment = type->alignment(); // use type's alignment
-
- //printf("sc->stc = %x\n", sc->stc);
- //printf("storage_class = x%x\n", storage_class);
-
- if (global.params.vcomplex)
- type->checkComplexTransition(loc);
-
- // Calculate type size + safety checks
- if (sc->func && !sc->intypeof)
- {
- if ((storage_class & STCgshared) && !isMember())
- {
- if (sc->func->setUnsafe())
- error("__gshared not allowed in safe functions; use shared");
- }
- }
-
- Dsymbol *parent = toParent();
-
- Type *tb = type->toBasetype();
- Type *tbn = tb->baseElemOf();
- if (tb->ty == Tvoid && !(storage_class & STClazy))
- {
- if (inferred)
- {
- error("type %s is inferred from initializer %s, and variables cannot be of type void",
- type->toChars(), _init->toChars());
- }
- else
- error("variables cannot be of type void");
- type = Type::terror;
- tb = type;
- }
- if (tb->ty == Tfunction)
- {
- error("cannot be declared to be a function");
- type = Type::terror;
- tb = type;
- }
- if (tb->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tb;
- if (!ts->sym->members)
- {
- error("no definition of struct %s", ts->toChars());
- }
- }
- if ((storage_class & STCauto) && !inferred)
- 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 = (_init && !_init->isVoidInitializer()) ? initializerToExpression(_init) : NULL;
- if (ie)
- ie = ::semantic(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 = arg->type->semantic(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);
- v->semantic(sc);
- VarExp *ve = new VarExp(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 = arg->type->semantic(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(loc, new DeclarationExp(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(_init->loc, iexps);
- }
-Lnomatch:
-
- if (ie && ie->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)ie;
- size_t tedim = te->exps->length;
- if (tedim != nelems)
- {
- ::error(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", 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 = _init ? _init->syntaxCopy() : NULL;
-
- VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti);
- v->storage_class |= STCtemp | storage_class;
- if (arg->storageClass & STCparameter)
- v->storage_class |= arg->storageClass;
- //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
- v->semantic(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(loc, v);
- (*exps)[i] = e;
- }
- TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps);
- v2->parent = this->parent;
- v2->isexp = true;
- aliassym = v2;
- semanticRun = PASSsemanticdone;
- return;
- }
-
- /* Storage class can modify the type
- */
- type = type->addStorageClass(storage_class);
-
- /* Adjust storage class to reflect type
- */
- if (type->isConst())
- {
- storage_class |= STCconst;
- if (type->isShared())
- storage_class |= STCshared;
- }
- else if (type->isImmutable())
- storage_class |= STCimmutable;
- else if (type->isShared())
- storage_class |= STCshared;
- else if (type->isWild())
- storage_class |= STCwild;
-
- if (StorageClass stc = storage_class & (STCsynchronized | STCoverride | STCabstract | STCfinal))
- {
- if (stc == STCfinal)
- error("cannot be final, perhaps you meant const?");
- else
- {
- OutBuffer buf;
- stcToBuffer(&buf, stc);
- error("cannot be %s", buf.peekChars());
- }
- storage_class &= ~stc; // strip off
- }
-
- if (storage_class & STCscope)
- {
- StorageClass stc = storage_class & (STCstatic | STCextern | STCmanifest | STCtls | STCgshared);
- if (stc)
- {
- OutBuffer buf;
- stcToBuffer(&buf, stc);
- error("cannot be 'scope' and '%s'", buf.peekChars());
- }
- else if (isMember())
- {
- error("field cannot be 'scope'");
- }
- else if (!type->hasPointers())
- {
- storage_class &= ~STCscope; // silently ignore; may occur in generic code
- }
- }
-
- if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe))
- {
- }
- else
- {
- AggregateDeclaration *aad = parent->isAggregateDeclaration();
- if (aad)
- {
- if (global.params.vfield &&
- storage_class & (STCconst | STCimmutable) && _init && !_init->isVoidInitializer())
- {
- const char *s = (storage_class & STCimmutable) ? "immutable" : "const";
- message(loc, "`%s.%s` is `%s` field", ad->toPrettyChars(), toChars(), s);
- }
- storage_class |= STCfield;
- if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor)
- {
- if (!isThisDeclaration() && !_init)
- aad->noDefaultCtor = true;
- }
- }
-
- InterfaceDeclaration *id = parent->isInterfaceDeclaration();
- if (id)
- {
- error("field not allowed in interface");
- }
- else if (aad && aad->sizeok == SIZEOKdone)
- {
- 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 && storage_class != STCundefined)
- {
- error("cannot use template to add field to aggregate '%s'", ad2->toChars());
- }
- }
- }
-
- if ((storage_class & (STCref | STCparameter | STCforeach | STCtemp | STCresult)) == STCref && ident != Id::This)
- {
- error("only parameters or foreach declarations can be ref");
- }
-
- if (type->hasWild())
- {
- if (storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) ||
- isDataseg()
- )
- {
- 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)
- {
- error("inout variables can only be declared inside inout functions");
- }
- }
- }
-
- if (!(storage_class & (STCctfe | STCref | STCresult)) && tbn->ty == Tstruct &&
- ((TypeStruct *)tbn)->sym->noDefaultCtor)
- {
- if (!_init)
- {
- if (isField())
- {
- /* For fields, we'll check the constructor later to make sure it is initialized
- */
- storage_class |= STCnodefaultctor;
- }
- else if (storage_class & STCparameter)
- ;
- else
- error("default construction is disabled for type %s", type->toChars());
- }
- }
-
- FuncDeclaration *fd = parent->isFuncDeclaration();
- if (type->isscope() && !(storage_class & STCnodtor))
- {
- if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd)
- {
- error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope");
- }
-
- if (!(storage_class & STCscope))
- {
- if (!(storage_class & STCparameter) && ident != Id::withSym)
- error("reference to scope class must be scope");
- }
- }
-
- // Calculate type size + safety checks
- if (sc->func && !sc->intypeof)
- {
- if (_init && _init->isVoidInitializer() && type->hasPointers()) // get type size
- {
- if (sc->func->setUnsafe())
- error("void initializers for pointers not allowed in safe functions");
- }
- else if (!_init &&
- !(storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield | STCparameter)) &&
- type->hasVoidInitPointers())
- {
- if (sc->func->setUnsafe())
- error("void initializers for pointers not allowed in safe functions");
- }
- }
-
- if (!_init && !fd)
- {
- // If not mutable, initializable by constructor only
- storage_class |= STCctorinit;
- }
-
- if (_init)
- storage_class |= STCinit; // remember we had an explicit initializer
- else if (storage_class & STCmanifest)
- error("manifest constants must have initializers");
-
- bool isBlit = false;
- d_uns64 sz = 0;
- if (!_init && !sc->inunion && !(storage_class & (STCstatic | STCgshared | STCextern)) && fd &&
- (!(storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult))
- || (storage_class & STCout)) &&
- (sz = type->size()) != 0)
- {
- // Provide a default initializer
- //printf("Providing default initializer for '%s'\n", toChars());
- if (sz == SIZE_INVALID && type->ty != Terror)
- error("size of type %s is invalid", type->toChars());
-
- Type *tv = 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(loc, sc, ((TypeStruct *)tbn)->sym);
-
- Expression *e = tv->defaultInitLiteral(loc);
- e = new BlitExp(loc, new VarExp(loc, this), e);
- e = ::semantic(e, sc);
- _init = new ExpInitializer(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(loc, 0, Type::tint32);
- e = new BlitExp(loc, new VarExp(loc, this), e);
- e->type = type; // don't type check this, it would fail
- _init = new ExpInitializer(loc, e);
- goto Ldtor;
- }
- if (type->baseElemOf()->ty == Tvoid)
- {
- error("%s does not have a default initializer", type->toChars());
- }
- else if (Expression *e = type->defaultInit(loc))
- {
- _init = new ExpInitializer(loc, e);
- }
- // Default initializer is always a blit
- isBlit = true;
- }
-
- if (_init)
- {
- sc = sc->push();
- sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCnogc | STCref | STCdisable);
-
- ExpInitializer *ei = _init->isExpInitializer();
- if (ei) // Bugzilla 13424: Preset the required type to fail in FuncLiteralDeclaration::semantic3
- ei->exp = inferType(ei->exp, 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 &&
- !(storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) &&
- !_init->isVoidInitializer())
- {
- //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars());
- if (!ei)
- {
- ArrayInitializer *ai = _init->isArrayInitializer();
- Expression *e;
- if (ai && tb->ty == Taarray)
- e = ai->toAssocArrayLiteral();
- else
- e = initializerToExpression(_init);
- if (!e)
- {
- // Run semantic, but don't need to interpret
- _init = ::semantic(_init, sc, type, INITnointerpret);
- e = initializerToExpression(_init);
- if (!e)
- {
- error("is not a static and cannot have static initializer");
- e = new ErrorExp();
- }
- }
- ei = new ExpInitializer(_init->loc, e);
- _init = ei;
- }
-
- Expression *exp = ei->exp;
- Expression *e1 = new VarExp(loc, this);
- if (isBlit)
- exp = new BlitExp(loc, e1, exp);
- else
- exp = new ConstructExp(loc, e1, exp);
- canassign++;
- exp = ::semantic(exp, sc);
- canassign--;
- exp = exp->optimize(WANTvalue);
-
- if (exp->op == TOKerror)
- {
- _init = new ErrorInitializer();
- ei = NULL;
- }
- else
- ei->exp = exp;
-
- if (ei && 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 (type->toBasetype()->ty == Tclass)
- {
- if (ne->newargs && ne->newargs->length > 1)
- {
- mynew = true;
- }
- else
- {
- ne->onstack = true;
- 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
- _init = ::semantic(_init, sc, type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
- }
- }
- else if (parent->isAggregateDeclaration())
- {
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- }
- else if (storage_class & (STCconst | STCimmutable | STCmanifest) ||
- type->isConst() || 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;
- inuse++;
- if (ei)
- {
- Expression *exp = ei->exp->syntaxCopy();
-
- bool needctfe = isDataseg() || (storage_class & STCmanifest);
- if (needctfe) sc = sc->startCTFE();
- exp = ::semantic(exp, sc);
- exp = resolveProperties(sc, exp);
- if (needctfe) sc = sc->endCTFE();
-
- Type *tb2 = 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())
- error("of type struct %s uses this(this), which is not allowed in static initialization", tb2->toChars());
- }
- }
- ei->exp = exp;
- }
- _init = ::semantic(_init, sc, type, INITinterpret);
- inuse--;
- if (global.errors > errors)
- {
- _init = new ErrorInitializer();
- type = Type::terror;
- }
- }
- else
- {
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- }
- }
- sc = sc->pop();
- }
-
-Ldtor:
- /* Build code to execute destruction, if necessary
- */
- edtor = callScopeDtor(sc);
- if (edtor)
- {
- if (sc->func && storage_class & (STCstatic | STCgshared))
- edtor = ::semantic(edtor, sc->_module->_scope);
- else
- edtor = ::semantic(edtor, sc);
-
-#if 0 // currently disabled because of std.stdio.stdin, stdout and stderr
- if (isDataseg() && !(storage_class & STCextern))
- error("static storage variables cannot have destructors");
-#endif
- }
-
- semanticRun = PASSsemanticdone;
-
- if (type->toBasetype()->ty == Terror)
- errors = true;
-
- if (sc->scopesym && !sc->scopesym->isAggregateDeclaration())
- {
- for (ScopeDsymbol *sym = sc->scopesym; sym && endlinnum == 0;
- sym = sym->parent ? sym->parent->isScopeDsymbol() : NULL)
- endlinnum = sym->endlinnum;
- }
-}
-
-void VarDeclaration::semantic2(Scope *sc)
-{
- if (semanticRun < PASSsemanticdone && inuse)
- return;
-
- //printf("VarDeclaration::semantic2('%s')\n", toChars());
-
- if (_init && !toParent()->isFuncDeclaration())
- {
- inuse++;
- // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
- _init = ::semantic(_init, sc, type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
- inuse--;
- }
- if (_init && storage_class & STCmanifest)
- {
- /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
- * Scan initializer looking for them. Issue error if found.
- */
- if (ExpInitializer *ei = _init->isExpInitializer())
- {
- struct EnumInitializer
- {
- static bool arrayHasInvalidEnumInitializer(Expressions *elems)
- {
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *e = (*elems)[i];
- if (e && hasInvalidEnumInitializer(e))
- return true;
- }
- return false;
- }
-
- static bool hasInvalidEnumInitializer(Expression *e)
- {
- if (e->op == TOKclassreference)
- return true;
- if (e->op == TOKaddress && ((AddrExp *)e)->e1->op == TOKstructliteral)
- return true;
- if (e->op == TOKarrayliteral)
- return arrayHasInvalidEnumInitializer(((ArrayLiteralExp *)e)->elements);
- if (e->op == TOKstructliteral)
- return arrayHasInvalidEnumInitializer(((StructLiteralExp *)e)->elements);
- if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
- return arrayHasInvalidEnumInitializer(ae->values) ||
- arrayHasInvalidEnumInitializer(ae->keys);
- }
- return false;
- }
- };
- if (EnumInitializer::hasInvalidEnumInitializer(ei->exp))
- error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
- }
- }
- else if (_init && isThreadlocal())
- {
- if ((type->ty == Tclass) && type->isMutable() && !type->isShared())
- {
- ExpInitializer *ei = _init->isExpInitializer();
- if (ei && ei->exp->op == TOKclassreference)
- error("is mutable. Only const or immutable class thread local variable are allowed, not %s", type->toChars());
- }
- else if (type->ty == Tpointer && type->nextOf()->ty == Tstruct && type->nextOf()->isMutable() &&!type->nextOf()->isShared())
- {
- ExpInitializer *ei = _init->isExpInitializer();
- if (ei && ei->exp->op == TOKaddress && ((AddrExp *)ei->exp)->e1->op == TOKstructliteral)
- {
- error("is a pointer to mutable struct. Only pointers to const, immutable or shared struct thread local variable are allowed, not %s", type->toChars());
- }
- }
- }
- semanticRun = PASSsemantic2done;
-}
-
void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
{
//printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars());
{
//printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
if ((!type || !type->deco) && _scope)
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
assert(this != aliassym);
Dsymbol *s = aliassym ? aliassym->toAlias() : this;
if (_scope)
{
inuse++;
- _init = ::semantic(_init, _scope, type, INITinterpret);
+ _init = initializerSemantic(_init, _scope, type, INITinterpret);
_scope = NULL;
inuse--;
}
return NULL;
}
-void TypeInfoDeclaration::semantic(Scope *)
-{
- assert(linkage == LINKc);
-}
-
const char *TypeInfoDeclaration::toChars()
{
//printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo->toChars());
/* 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.
Ensure syntaxCopy();
static Ensures *arraySyntaxCopy(Ensures *a);
};
+class AliasDeclaration;
class FuncDeclaration;
class ExpInitializer;
class StructDeclaration;
void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs);
int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
+void aliasSemantic(AliasDeclaration *ds, Scope *sc);
void ObjectNotFound(Identifier *id);
DString mangleOverride; // overridden symbol with pragma(mangle, "...")
Declaration(Identifier *id);
- void semantic(Scope *sc);
const char *kind() const;
d_uns64 size(Loc loc);
bool checkDisabled(Loc loc, Scope *sc, bool isAliasedDeclaration = false);
AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s);
static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
- void aliasSemantic(Scope *sc);
bool overloadInsert(Dsymbol *s);
const char *kind() const;
Type *getType();
OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads = true);
const char *kind() const;
- void semantic(Scope *sc);
bool equals(RootObject *o);
bool overloadInsert(Dsymbol *s);
VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init);
static VarDeclaration *create(Loc loc, Type *t, Identifier *id, Initializer *init);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
- void semantic2(Scope *sc);
const char *kind() const;
AggregateDeclaration *isThis();
bool needThis();
TypeInfoDeclaration(Type *tinfo);
static TypeInfoDeclaration *create(Type *tinfo);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
const char *toChars();
TypeInfoDeclaration *isTypeInfoDeclaration() { return this; }
FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
static FuncDeclaration *create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
- void semantic3(Scope *sc);
bool functionSemantic();
bool functionSemantic3();
bool checkForwardRef(Loc loc);
bool hasNestedFrameRefs();
void buildResultVar(Scope *sc, Type *tret);
Statement *mergeFrequire(Statement *);
+ static bool needsFensure(FuncDeclaration *fd);
+ void buildEnsureRequire();
Statement *mergeFensure(Statement *, Identifier *oid);
ParameterList getParameterList();
public:
CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
const char *kind() const;
const char *toChars();
bool isVirtual();
public:
PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
bool isVirtual();
bool addPreInvariant();
bool addPostInvariant();
DtorDeclaration(Loc loc, Loc endloc);
DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
const char *kind() const;
const char *toChars();
bool isVirtual();
StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
AggregateDeclaration *isThis();
bool isVirtual();
bool addPreInvariant();
StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
AggregateDeclaration *isThis();
bool isVirtual();
bool hasStaticCtorOrDtor();
public:
InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id = NULL);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
bool isVirtual();
bool addPreInvariant();
bool addPostInvariant();
UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
AggregateDeclaration *isThis();
bool isVirtual();
bool addPreInvariant();
NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, VarArg varargs);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
const char *kind() const;
bool isVirtual();
bool addPreInvariant();
DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
const char *kind() const;
bool isDelete();
bool isVirtual();
/* 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.
bool walkPostorder(Expression *e, StoppableVisitor *v);
void lambdaSetParent(Expression *e, Scope *sc);
bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
-Expression *semantic(Expression *e, Scope *sc);
/********************************************
* Convert from expression to delegate that returns the expression,
fld->fbody = s;
e = new FuncExp(loc, fld);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
/* 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.
#include "declaration.h"
#include "init.h"
-Expression *semantic(Expression *e, Scope *sc);
-
/********************************* EnumDeclaration ****************************/
EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
added = true;
}
-
-void EnumDeclaration::semantic(Scope *sc)
-{
- //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars());
- //printf("EnumDeclaration::semantic() %p %s\n", this, toChars());
- if (semanticRun >= PASSsemanticdone)
- return; // semantic() already completed
- if (semanticRun == PASSsemantic)
- {
- assert(memtype);
- ::error(loc, "circular reference to enum base type %s", memtype->toChars());
- errors = true;
- semanticRun = PASSsemanticdone;
- return;
- }
- unsigned dprogress_save = Module::dprogress;
-
- Scope *scx = NULL;
- if (_scope)
- {
- sc = _scope;
- scx = _scope; // save so we don't make redundant copies
- _scope = NULL;
- }
-
- if (!sc)
- return;
-
- parent = sc->parent;
- type = type->semantic(loc, sc);
-
- protection = sc->protection;
- if (sc->stc & STCdeprecated)
- isdeprecated = true;
- userAttribDecl = sc->userAttribDecl;
-
- semanticRun = PASSsemantic;
-
- if (!members && !memtype) // enum ident;
- {
- semanticRun = PASSsemanticdone;
- return;
- }
-
- if (!symtab)
- 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 (memtype)
- {
- memtype = memtype->semantic(loc, sc);
-
- /* Check to see if memtype is forward referenced
- */
- if (memtype->ty == Tenum)
- {
- EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
- if (!sym->memtype || !sym->members || !sym->symtab || sym->_scope)
- {
- // memtype is forward referenced, so try again later
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- _scope->_module->addDeferredSemantic(this);
- Module::dprogress = dprogress_save;
- //printf("\tdeferring %s\n", toChars());
- semanticRun = PASSinit;
- return;
- }
- }
- if (memtype->ty == Tvoid)
- {
- error("base type must not be void");
- memtype = Type::terror;
- }
- if (memtype->ty == Terror)
- {
- errors = true;
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->errors = true; // poison all the members
- }
- }
- semanticRun = PASSsemanticdone;
- return;
- }
- }
-
- semanticRun = PASSsemanticdone;
-
- if (!members) // enum ident : memtype;
- return;
-
- if (members->length == 0)
- {
- error("enum %s must have at least one member", toChars());
- errors = true;
- return;
- }
-
- Module::dprogress++;
-
- Scope *sce;
- if (isAnonymous())
- sce = sc;
- else
- {
- sce = sc->push(this);
- sce->parent = this;
- }
- sce = sce->startCTFE();
- sce->setNoFree(); // needed for getMaxMinValue()
-
- /* Each enum member gets the sce scope
- */
- for (size_t i = 0; i < members->length; i++)
- {
- EnumMember *em = (*members)[i]->isEnumMember();
- if (em)
- em->_scope = sce;
- }
-
- if (!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 (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 = this;
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- EnumMember *em = (*members)[i]->isEnumMember();
- if (em)
- {
- em->ed = this;
- em->addMember(sc, scopesym);
- }
- }
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- EnumMember *em = (*members)[i]->isEnumMember();
- if (em)
- em->semantic(em->_scope);
- }
- //printf("defaultval = %lld\n", defaultval);
-
- //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
- //printf("members = %s\n", members->toChars());
-}
-
/******************************
* Get the value of the .max/.min property as an Expression
* Input:
goto Ldone;
if (_scope)
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
if (errors)
goto Lerrors;
if (semanticRun == PASSinit || !members)
*/
Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval);
inuse++;
- ec = ::semantic(ec, em->_scope);
+ ec = expressionSemantic(ec, em->_scope);
inuse--;
ec = ec->ctfeInterpret();
if (ec->toInteger())
return defaultval;
if (_scope)
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
if (errors)
goto Lerrors;
if (semanticRun == PASSinit || !members)
* just the base type
*/
if (memtype)
- memtype = memtype->semantic(loc, _scope);
+ memtype = typeSemantic(memtype, loc, _scope);
else
{
if (!isAnonymous() && members)
if (_scope)
{
// Try one last time to resolve this enum
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
}
if (!members || !symtab || _scope)
{
- error("is forward referenced when looking for '%s'", ident->toChars());
+ error("is forward referenced when looking for `%s`", ident->toChars());
//*(char*)0=0;
return NULL;
}
return "enum member";
}
-void EnumMember::semantic(Scope *sc)
-{
- //printf("EnumMember::semantic() %s\n", toChars());
- if (errors || semanticRun >= PASSsemanticdone)
- return;
- if (semanticRun == PASSsemantic)
- {
- error("circular reference to enum member");
- Lerrors:
- errors = true;
- semanticRun = PASSsemanticdone;
- return;
- }
- assert(ed);
-
- ed->semantic(sc);
- if (ed->errors)
- goto Lerrors;
-
- if (errors || semanticRun >= PASSsemanticdone)
- return;
-
- if (_scope)
- sc = _scope;
- if (!sc)
- return;
-
- semanticRun = PASSsemantic;
-
- protection = ed->isAnonymous() ? ed->protection : Prot(Prot::public_);
- linkage = LINKd;
- storage_class |= STCmanifest;
-
- // https://issues.dlang.org/show_bug.cgi?id=9701
- if (ed->isAnonymous())
- {
- if (userAttribDecl)
- userAttribDecl->userAttribDecl = ed->userAttribDecl;
- else
- userAttribDecl = ed->userAttribDecl;
- }
-
- // The first enum member is special
- bool first = (this == (*ed->members)[0]);
-
- if (origType)
- {
- origType = origType->semantic(loc, sc);
- type = origType;
- assert(value()); // "type id;" is not a valid enum member declaration
- }
-
- if (value())
- {
- Expression *e = value();
- assert(e->dyncast() == DYNCAST_EXPRESSION);
- e = ::semantic(e, sc);
- e = resolveProperties(sc, e);
- e = e->ctfeInterpret();
- if (e->op == TOKerror)
- goto Lerrors;
- if (first && !ed->memtype && !ed->isAnonymous())
- {
- ed->memtype = e->type;
- if (ed->memtype->ty == Terror)
- {
- ed->errors = true;
- goto Lerrors;
- }
- if (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 < ed->members->length; i++)
- {
- EnumMember *em = (*ed->members)[i]->isEnumMember();
- if (!em || em == this || em->semanticRun < PASSsemanticdone || em->origType)
- continue;
-
- //printf("[%d] em = %s, em->semanticRun = %d\n", i, toChars(), em->semanticRun);
- Expression *ev = em->value();
- ev = ev->implicitCastTo(sc, ed->memtype);
- ev = ev->ctfeInterpret();
- ev = ev->castTo(sc, ed->type);
- if (ev->op == TOKerror)
- ed->errors = true;
- em->value() = ev;
- }
- if (ed->errors)
- {
- ed->memtype = Type::terror;
- goto Lerrors;
- }
- }
- }
-
- if (ed->memtype && !origType)
- {
- e = e->implicitCastTo(sc, ed->memtype);
- e = e->ctfeInterpret();
-
- // save origValue for better json output
- origValue = e;
-
- if (!ed->isAnonymous())
- {
- e = e->castTo(sc, ed->type);
- e = e->ctfeInterpret();
- }
- }
- else if (origType)
- {
- e = e->implicitCastTo(sc, origType);
- e = e->ctfeInterpret();
- assert(ed->isAnonymous());
-
- // save origValue for better json output
- origValue = e;
- }
- value() = e;
- }
- else if (first)
- {
- Type *t;
- if (ed->memtype)
- t = ed->memtype;
- else
- {
- t = Type::tint32;
- if (!ed->isAnonymous())
- ed->memtype = t;
- }
- Expression *e = new IntegerExp(loc, 0, Type::tint32);
- e = e->implicitCastTo(sc, t);
- e = e->ctfeInterpret();
-
- // save origValue for better json output
- origValue = e;
-
- if (!ed->isAnonymous())
- {
- e = e->castTo(sc, ed->type);
- e = e->ctfeInterpret();
- }
- 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 < ed->members->length; i++)
- {
- EnumMember *em = (*ed->members)[i]->isEnumMember();
- if (em)
- {
- if (em == this)
- break;
- emprev = em;
- }
- }
- assert(emprev);
- if (emprev->semanticRun < PASSsemanticdone) // if forward reference
- emprev->semantic(emprev->_scope); // resolve it
- if (emprev->errors)
- goto Lerrors;
-
- Expression *eprev = emprev->value();
- Type *tprev = eprev->type->equals(ed->type) ? ed->memtype : eprev->type;
-
- Expression *emax = tprev->getProperty(ed->loc, Id::max, 0);
- emax = ::semantic(emax, sc);
- emax = emax->ctfeInterpret();
-
- // Set value to (eprev + 1).
- // But first check that (eprev != emax)
- assert(eprev);
- Expression *e = new EqualExp(TOKequal, loc, eprev, emax);
- e = ::semantic(e, sc);
- e = e->ctfeInterpret();
- if (e->toInteger())
- {
- error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev->ed->toChars(), emprev->toChars(), ed->type->toBasetype()->toChars());
- goto Lerrors;
- }
-
- // Now set e to (eprev + 1)
- e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type::tint32));
- e = ::semantic(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);
- origValue = new AddExp(loc, emprev->origValue, new IntegerExp(loc, 1, Type::tint32));
- origValue = ::semantic(origValue, sc);
- origValue = 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, loc, e, eprev);
- etest = ::semantic(etest, sc);
- etest = etest->ctfeInterpret();
- if (etest->toInteger())
- {
- error("has inexact value, due to loss of precision");
- goto Lerrors;
- }
- }
- value() = e;
- }
- if (!origType)
- type = value()->type;
-
- assert(origValue);
- semanticRun = PASSsemanticdone;
-}
-
Expression *EnumMember::getVarExp(Loc loc, Scope *sc)
{
- semantic(sc);
+ dsymbolSemantic(this, sc);
if (errors)
return new ErrorExp();
checkDisabled(loc, sc);
if (errors)
return new ErrorExp();
Expression *e = new VarExp(loc, this);
- return ::semantic(e, sc);
+ return expressionSemantic(e, sc);
}
/* 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.
}
}
-void Import::semantic(Scope *sc)
-{
- //printf("Import::semantic('%s') %s\n", toPrettyChars(), id->toChars());
- if (semanticRun > PASSinit)
- return;
-
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
- if (!sc)
- return;
-
- semanticRun = PASSsemantic;
-
- // Load if not already done so
- if (!mod)
- {
- load(sc);
- if (mod)
- mod->importAll(NULL);
- }
-
- if (mod)
- {
- // Modules need a list of each imported module
- //printf("%s imports %s\n", sc->_module->toChars(), mod->toChars());
- sc->_module->aimports.push(mod);
-
- if (sc->explicitProtection)
- protection = sc->protection;
-
- if (!aliasId && !names.length) // neither a selective nor a renamed import
- {
- ScopeDsymbol *scopesym = NULL;
- if (sc->explicitProtection)
- protection = sc->protection.kind;
- for (Scope *scd = sc; scd; scd = scd->enclosing)
- {
- if (!scd->scopesym)
- continue;
- scopesym = scd->scopesym;
- break;
- }
-
- if (!isstatic)
- {
- scopesym->importScope(mod, protection);
- }
-
- // Mark the imported packages as accessible from the current
- // scope. This access check is necessary when using FQN b/c
- // we're using a single global package tree. See Bugzilla 313.
- if (packages)
- {
- // import a.b.c.d;
- Package *p = pkg; // a
- scopesym->addAccessiblePackage(p, protection);
- for (size_t i = 1; i < packages->length; i++) // [b, c]
- {
- Identifier *id = (*packages)[i];
- p = (Package *) p->symtab->lookup(id);
- scopesym->addAccessiblePackage(p, protection);
- }
- }
- scopesym->addAccessiblePackage(mod, protection); // d
- }
-
- mod->semantic(NULL);
-
- if (mod->needmoduleinfo)
- {
- //printf("module4 %s because of %s\n", sc->_module->toChars(), mod->toChars());
- sc->_module->needmoduleinfo = 1;
- }
-
- sc = sc->push(mod);
- sc->protection = protection;
- for (size_t i = 0; i < aliasdecls.length; i++)
- {
- AliasDeclaration *ad = aliasdecls[i];
- //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i]->toChars(), names[i]->toChars(), ad->_scope);
- if (mod->search(loc, names[i]))
- {
- ad->semantic(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 = mod->search_correct(names[i]);
- if (s)
- mod->error(loc, "import '%s' not found, did you mean %s '%s'?", names[i]->toChars(), s->kind(), s->toChars());
- else
- mod->error(loc, "import '%s' not found", names[i]->toChars());
- ad->type = Type::terror;
- }
- }
- sc = sc->pop();
- }
-
- 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 &&
- !(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, protection);
- ob->writeByte(' ');
- if (isstatic)
- {
- stcToBuffer(ob, STCstatic);
- ob->writeByte(' ');
- }
- ob->writestring(": ");
-
- if (packages)
- {
- for (size_t i = 0; i < packages->length; i++)
- {
- Identifier *pid = (*packages)[i];
- ob->printf("%s.", pid->toChars());
- }
- }
-
- ob->writestring(id->toChars());
- ob->writestring(" (");
- if (mod)
- escapePath(ob, mod->srcfile->toChars());
- else
- ob->writestring("???");
- ob->writeByte(')');
-
- for (size_t i = 0; i < names.length; i++)
- {
- if (i == 0)
- ob->writeByte(':');
- else
- ob->writeByte(',');
-
- Identifier *name = names[i];
- Identifier *alias = aliases[i];
-
- if (!alias)
- {
- ob->printf("%s", name->toChars());
- alias = name;
- }
- else
- ob->printf("%s=%s", alias->toChars(), name->toChars());
- }
-
- if (aliasId)
- ob->printf(" -> %s", aliasId->toChars());
-
- ob->writenl();
- }
-
- //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
-}
-
-void Import::semantic2(Scope *sc)
-{
- //printf("Import::semantic2('%s')\n", toChars());
- if (mod)
- {
- mod->semantic2(NULL);
- if (mod->needmoduleinfo)
- {
- //printf("module5 %s because of %s\n", sc->_module->toChars(), mod->toChars());
- if (sc)
- sc->_module->needmoduleinfo = 1;
- }
- }
-}
-
Dsymbol *Import::toAlias()
{
if (aliasId)
{
load(NULL);
mod->importAll(NULL);
- mod->semantic(NULL);
+ dsymbolSemantic(mod, NULL);
}
// Forward it to the package/module
/* 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.
bool walkPostorder(Expression *e, StoppableVisitor *v);
Expression *interpret(Statement *s, InterState *istate);
Expression *interpret(Expression *e, InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
-Expression *semantic(Expression *e, Scope *sc);
-Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
static Expression *interpret(UnionExp *pue, Expression *e, InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
static Expression *interpret(UnionExp *pue, Statement *s, InterState *istate);
{
// error, no this. Prevent segfault.
// Here should be unreachable by the strict 'this' check in front-end.
- fd->error("need 'this' to access member %s", fd->toChars());
+ fd->error("need `this` to access member %s", fd->toChars());
return CTFEExp::cantexp;
}
if (!istate && (fparam->storageClass & STCout))
{
// initializing an out parameter involves writing to it.
- earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars());
+ earg->error("global %s cannot be passed as an `out` parameter at compile time", earg->toChars());
return CTFEExp::cantexp;
}
// Convert all reference arguments into lvalue references
result->op == TOKclassreference);
return;
}
- e->error("value of 'this' is not known at compile time");
+ e->error("value of `this` is not known at compile time");
result = CTFEExp::cantexp;
}
if (!v->originalType && v->semanticRun < PASSsemanticdone) // semantic() not yet run
{
- v->semantic(NULL);
+ dsymbolSemantic(v, NULL);
if (v->type->ty == Terror)
return CTFEExp::cantexp;
}
{
if (v->inuse)
{
- error(loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ error(loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
return CTFEExp::cantexp;
}
if (v->_scope)
{
v->inuse++;
- v->_init = ::semantic(v->_init, v->_scope, v->type, INITinterpret); // might not be run on aggregate members
+ v->_init = initializerSemantic(v->_init, v->_scope, v->type, INITinterpret); // might not be run on aggregate members
v->inuse--;
}
e = initializerToExpression(v->_init, v->type);
e = s->dsym->type->defaultInitLiteral(loc);
if (e->op == TOKerror)
error(loc, "CTFE failed because of previous errors in %s.init", s->toChars());
- e = ::semantic(e, NULL);
+ e = expressionSemantic(e, NULL);
if (e->op == TOKerror)
e = CTFEExp::cantexp;
else // Convert NULL to CTFEExp
if (result->op == TOKnull)
{
- e->error("null pointer dereference evaluating typeid. '%s' is null", ex->toChars());
+ e->error("null pointer dereference evaluating typeid. `%s` is null", ex->toChars());
result = CTFEExp::cantexp;
return;
}
VarDeclaration *v = c->fields[i];
if (v->inuse)
{
- e->error("circular reference to '%s'", v->toPrettyChars());
+ e->error("circular reference to `%s`", v->toPrettyChars());
result = CTFEExp::cantexp;
return;
}
{
if (result->op != TOKclassreference)
{
- e->error("delete on invalid class reference '%s'", result->toChars());
+ e->error("delete on invalid class reference `%s`", result->toChars());
result = CTFEExp::cantexp;
return;
}
if (result->op != TOKaddress ||
((AddrExp *)result)->e1->op != TOKstructliteral)
{
- e->error("delete on invalid struct pointer '%s'", result->toChars());
+ e->error("delete on invalid struct pointer `%s`", result->toChars());
result = CTFEExp::cantexp;
return;
}
{
if (result->op != TOKarrayliteral)
{
- e->error("delete on invalid struct array '%s'", result->toChars());
+ e->error("delete on invalid struct array `%s`", result->toChars());
result = CTFEExp::cantexp;
return;
}
if (result->op != TOKaddress)
{
if (result->op == TOKnull)
- e->error("dereference of null pointer '%s'", e->e1->toChars());
+ e->error("dereference of null pointer `%s`", e->e1->toChars());
else
- e->error("dereference of invalid pointer '%s'", result->toChars());
+ e->error("dereference of invalid pointer `%s`", result->toChars());
result = CTFEExp::cantexp;
return;
}
if (ex->op == TOKnull)
{
if (ex->type->toBasetype()->ty == Tclass)
- e->error("class '%s' is null and cannot be dereferenced", e->e1->toChars());
+ e->error("class `%s` is null and cannot be dereferenced", e->e1->toChars());
else
- e->error("CTFE internal error: null this '%s'", e->e1->toChars());
+ e->error("CTFE internal error: null this `%s`", e->e1->toChars());
result = CTFEExp::cantexp;
return;
}
}
else if (e->op == TOKvoid)
{
- error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
+ error(loc, "uninitialized variable `%s` cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
return new ErrorExp();
}
/* 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.
/* 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.
/* 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.
Dsymbols Module::deferred3; // deferred Dsymbol's needing semantic3() run on them
unsigned Module::dprogress;
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
-
void Module::_init()
{
modules = new DsymbolTable();
sc->pop(); // 2 pops because Scope::createGlobal() created 2
}
-void Module::semantic(Scope *)
-{
- if (semanticRun != PASSinit)
- return;
-
- //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
- 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 = _scope; // see if already got one from importAll()
- if (!sc)
- {
- Scope::createGlobal(this); // 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 < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
-
- //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars());
- s->semantic(sc);
- runDeferredSemantic();
- }
-
- if (userAttribDecl)
- {
- userAttribDecl->semantic(sc);
- }
-
- if (!_scope)
- {
- sc = sc->pop();
- sc->pop(); // 2 pops because Scope::createGlobal() created 2
- }
- semanticRun = PASSsemanticdone;
- //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
-}
-
-void Module::semantic2(Scope*)
-{
- //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
- if (semanticRun != PASSsemanticdone) // semantic() not completed yet - could be recursive call
- return;
- semanticRun = PASSsemantic2;
-
- // 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 = Scope::createGlobal(this); // create root scope
- //printf("Module = %p\n", sc.scopesym);
-
- // Pass 2 semantic routines: do initializers and function bodies
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic2(sc);
- }
-
- if (userAttribDecl)
- {
- userAttribDecl->semantic2(sc);
- }
-
- sc = sc->pop();
- sc->pop();
- semanticRun = PASSsemantic2done;
- //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
-}
-
-void Module::semantic3(Scope*)
-{
- //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
- if (semanticRun != PASSsemantic2done)
- return;
- semanticRun = PASSsemantic3;
-
- // 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 = Scope::createGlobal(this); // create root scope
- //printf("Module = %p\n", sc.scopesym);
-
- // Pass 3 semantic routines: do initializers and function bodies
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars());
- s->semantic3(sc);
-
- runDeferredSemantic2();
- }
-
- if (userAttribDecl)
- {
- userAttribDecl->semantic3(sc);
- }
-
- sc = sc->pop();
- sc->pop();
- semanticRun = PASSsemantic3done;
-}
-
/**********************************
* Determine if we need to generate an instance of ModuleInfo
* for this Module.
{
Dsymbol *s = todo[i];
- s->semantic(NULL);
+ dsymbolSemantic(s, NULL);
//printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
}
//printf("\tdeferred.length = %d, len = %d, dprogress = %d\n", deferred.length, len, dprogress);
{
Dsymbol *s = (*a)[i];
//printf("[%d] %s semantic2a\n", i, s->toPrettyChars());
- s->semantic2(NULL);
+ semantic2(s, NULL);
if (global.errors)
break;
Dsymbol *s = (*a)[i];
//printf("[%d] %s semantic3a\n", i, s->toPrettyChars());
- s->semantic3(NULL);
+ semantic3(s, NULL);
if (global.errors)
break;
return isAncestorPackageOf(pkg->parent->isPackage());
}
-void Package::semantic(Scope *)
-{
- if (semanticRun < PASSsemanticdone)
- semanticRun = PASSsemanticdone;
-}
-
/****************************************************
* Input:
* packages[] the pkg1.pkg2 of pkg1.pkg2.mod
/* 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.
/** Recursively expand template mixin member docs into the scope. */
static void expandTemplateMixinComments(TemplateMixin *tm, OutBuffer *buf, Scope *sc)
{
- if (!tm->semanticRun) tm->semantic(sc);
+ if (!tm->semanticRun)
+ dsymbolSemantic(tm, sc);
TemplateDeclaration *td = (tm && tm->tempdecl) ?
tm->tempdecl->isTemplateDeclaration() : NULL;
if (td && td->members)
emitProtection(buf, ad->protection);
buf->printf("alias %s = ", ad->toChars());
- if (Dsymbol *s = ad->aliassym) // ident alias
+ if (Dsymbol *sa = ad->aliassym) // ident alias
{
- prettyPrintDsymbol(s, ad->parent);
+ prettyPrintDsymbol(sa, ad->parent);
}
else if (Type *type = ad->getType()) // type alias
{
/* 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.
/* 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.
ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
{
- warning(s->loc, "array 'length' hides other 'length' name in outer scope");
+ warning(s->loc, "array `length` hides other `length` name in outer scope");
}
if (pscopesym)
*pscopesym = sc->scopesym;
}
else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
{
- if (VarDeclaration *vd = ss->withstate->wthis)
+ if (VarDeclaration *wthis = ss->withstate->wthis)
{
if (lastVar)
- vd->lastVar = lastVar;
- lastVar = vd;
+ wthis->lastVar = lastVar;
+ lastVar = wthis;
}
return NULL;
}
/* 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.
ScopeDsymbol::setScope(sc);
}
-void AggregateDeclaration::semantic2(Scope *sc)
-{
- //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
- if (!members)
- return;
-
- if (_scope)
- {
- error("has forward references");
- return;
- }
-
- Scope *sc2 = newScope(sc);
-
- determineSize(loc);
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("\t[%d] %s\n", i, s->toChars());
- s->semantic2(sc2);
- }
-
- sc2->pop();
-}
-
-void AggregateDeclaration::semantic3(Scope *sc)
-{
- //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
- if (!members)
- return;
-
- StructDeclaration *sd = isStructDeclaration();
- if (!sc) // from runDeferredSemantic3 for TypeInfo generation
- {
- assert(sd);
- sd->semanticTypeInfoMembers();
- return;
- }
-
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic3(sc2);
- }
-
- sc2->pop();
-
- // don't do it for unused deprecated types
- // or error types
- if (!getRTInfo && Type::rtinfo &&
- (!isDeprecated() || global.params.useDeprecated != DIAGNOSTICerror) &&
- (type && type->ty != Terror))
- {
- // Evaluate: RTinfo!type
- Objects *tiargs = new Objects();
- tiargs->push(type);
- TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs);
-
- Scope *sc3 = ti->tempdecl->_scope->startCTFE();
- sc3->tinst = sc->tinst;
- sc3->minst = sc->minst;
- if (isDeprecated())
- sc3->stc |= STCdeprecated;
-
- ti->semantic(sc3);
- ti->semantic2(sc3);
- ti->semantic3(sc3);
- Expression *e = resolve(Loc(), sc3, ti->toAlias(), false);
-
- sc3->endCTFE();
-
- e = e->ctfeInterpret();
- getRTInfo = e;
- }
-
- if (sd)
- sd->semanticTypeInfoMembers();
- semanticRun = PASSsemantic3done;
-}
-
/***************************************
* Find all instance fields, then push them into `fields`.
*
AggregateDeclaration *ad = ((SV *)param)->agg;
if (v->semanticRun < PASSsemanticdone)
- v->semantic(NULL);
+ dsymbolSemantic(v, NULL);
// Note: Aggregate fields or size could have determined during v->semantic.
if (ad->sizeok != SIZEOKnone)
return 1;
}
if (_scope)
- semantic(NULL);
+ dsymbolSemantic(this, NULL);
// Determine the instance size of base class first.
if (ClassDeclaration *cd = isClassDeclaration())
xeq->semanticRun < PASSsemantic3done)
{
unsigned errors = global.startGagging();
- xeq->semantic3(xeq->_scope);
+ semantic3(xeq, xeq->_scope);
if (global.endGagging(errors))
xeq = xerreq;
}
xcmp->semanticRun < PASSsemantic3done)
{
unsigned errors = global.startGagging();
- xcmp->semantic3(xcmp->_scope);
+ semantic3(xcmp, xcmp->_scope);
if (global.endGagging(errors))
xcmp = xerrcmp;
}
ftostr->_scope &&
ftostr->semanticRun < PASSsemantic3done)
{
- ftostr->semantic3(ftostr->_scope);
+ semantic3(ftostr, ftostr->_scope);
}
if (xhash &&
xhash->_scope &&
xhash->semanticRun < PASSsemantic3done)
{
- xhash->semantic3(xhash->_scope);
+ semantic3(xhash, xhash->_scope);
}
if (postblit &&
postblit->_scope &&
postblit->semanticRun < PASSsemantic3done)
{
- postblit->semantic3(postblit->_scope);
+ semantic3(postblit, postblit->_scope);
}
if (dtor &&
dtor->_scope &&
dtor->semanticRun < PASSsemantic3done)
{
- dtor->semantic3(dtor->_scope);
+ semantic3(dtor, dtor->_scope);
}
}
{
CtorDeclaration *f = s->isCtorDeclaration();
if (f && f->semanticRun == PASSinit)
- f->semantic(NULL);
+ dsymbolSemantic(f, NULL);
return 0;
}
};
return ScopeDsymbol::syntaxCopy(sd);
}
-void StructDeclaration::semantic(Scope *sc)
-{
- //printf("StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
-
- //static int count; if (++count == 20) halt();
-
- if (semanticRun >= PASSsemanticdone)
- return;
- unsigned errors = global.errors;
-
- //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
- Scope *scx = NULL;
- if (_scope)
- {
- sc = _scope;
- scx = _scope; // save so we don't make redundant copies
- _scope = NULL;
- }
-
- if (!parent)
- {
- assert(sc->parent && sc->func);
- parent = sc->parent;
- }
- assert(parent && !isAnonymous());
-
- if (this->errors)
- type = Type::terror;
- if (semanticRun == PASSinit)
- type = type->addSTC(sc->stc | storage_class);
- type = type->semantic(loc, sc);
-
- if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
- {
- TemplateInstance *ti = ((TypeStruct *)type)->sym->isInstantiated();
- if (ti && isError(ti))
- ((TypeStruct *)type)->sym = this;
- }
-
- // Ungag errors when not speculative
- Ungag ungag = ungagSpeculative();
-
- if (semanticRun == PASSinit)
- {
- protection = sc->protection;
-
- alignment = sc->alignment();
-
- storage_class |= sc->stc;
- if (storage_class & STCdeprecated)
- isdeprecated = true;
- if (storage_class & STCabstract)
- error("structs, unions cannot be abstract");
- userAttribDecl = sc->userAttribDecl;
-
- if (sc->linkage == LINKcpp)
- classKind = ClassKind::cpp;
- }
- else if (symtab && !scx)
- {
- return;
- }
- semanticRun = PASSsemantic;
-
- if (!members) // if opaque declaration
- {
- semanticRun = PASSsemanticdone;
- return;
- }
- if (!symtab)
- {
- symtab = new DsymbolTable();
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
- s->addMember(sc, this);
- }
- }
-
- Scope *sc2 = newScope(sc);
-
- /* Set scope so if there are forward references, we still might be able to
- * resolve individual members like enums.
- */
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("struct: setScope %s %s\n", s->kind(), s->toChars());
- s->setScope(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->importAll(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic(sc2);
- }
-
- if (!determineFields())
- {
- assert(type->ty == Terror);
- sc2->pop();
- semanticRun = PASSsemanticdone;
- return;
- }
-
- /* Following special member functions creation needs semantic analysis
- * completion of sub-structs in each field types. For example, buildDtor
- * needs to check existence of elaborate dtor in type of each fields.
- * See the case in compilable/test14838.d
- */
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *v = fields[i];
- Type *tb = v->type->baseElemOf();
- if (tb->ty != Tstruct)
- continue;
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- if (sd->semanticRun >= PASSsemanticdone)
- continue;
-
- sc2->pop();
-
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- _scope->_module->addDeferredSemantic(this);
-
- //printf("\tdeferring %s\n", toChars());
- return;
- }
-
- /* Look for special member functions.
- */
- aggNew = (NewDeclaration *)search(Loc(), Id::classNew);
- aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);
-
- // Look for the constructor
- ctor = searchCtor();
-
- dtor = buildDtor(this, sc2);
- postblit = buildPostBlit(this, sc2);
-
- buildOpAssign(this, sc2);
- buildOpEquals(this, sc2);
-
- if (global.params.useTypeInfo && Type::dtypeinfo) // these functions are used for TypeInfo
- {
- xeq = buildXopEquals(this, sc2);
- xcmp = buildXopCmp(this, sc2);
- xhash = buildXtoHash(this, sc2);
- }
-
- inv = buildInv(this, sc2);
-
- Module::dprogress++;
- semanticRun = PASSsemanticdone;
- //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
-
- sc2->pop();
-
- if (ctor)
- {
- Dsymbol *scall = search(Loc(), Id::call);
- if (scall)
- {
- unsigned xerrors = global.startGagging();
- sc = sc->push();
- sc->tinst = NULL;
- sc->minst = NULL;
- FuncDeclaration *fcall = resolveFuncCall(loc, sc, scall, NULL, NULL, NULL, 1);
- sc = sc->pop();
- global.endGagging(xerrors);
-
- if (fcall && fcall->isStatic())
- {
- error(fcall->loc, "static opCall is hidden by constructors and can never be called");
- errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with static opCall.");
- }
- }
- }
-
- if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
- {
- // https://issues.dlang.org/show_bug.cgi?id=19024
- StructDeclaration *sd = ((TypeStruct *)type)->sym;
- error("already exists at %s. Perhaps in another function with the same name?", sd->loc.toChars());
- }
-
- if (global.errors != errors)
- {
- // The type is no good.
- type = Type::terror;
- this->errors = true;
- if (deferred)
- deferred->errors = true;
- }
-
- if (deferred && !global.gag)
- {
- deferred->semantic2(sc);
- deferred->semantic3(sc);
- }
-}
-
Dsymbol *StructDeclaration::search(const Loc &loc, Identifier *ident, int flags)
{
//printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
if (_scope && !symtab)
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
if (!members || !symtab) // opaque or semantic() is not yet called
{
- error("is forward referenced when looking for '%s'", ident->toChars());
+ error("is forward referenced when looking for `%s`", ident->toChars());
return NULL;
}
/* 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.
bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
-Expression *semantic(Expression *e, Scope *sc);
/****************************** Dsymbol ******************************/
{
}
-/*************************************
- * Does semantic analysis on the public face of declarations.
- */
-
-void Dsymbol::semantic(Scope *)
-{
- error("%p has no semantic routine", this);
-}
-
-/*************************************
- * Does semantic analysis on initializers and members of aggregates.
- */
-
-void Dsymbol::semantic2(Scope *)
-{
- // Most Dsymbols have no further semantic analysis needed
-}
-
-/*************************************
- * Does semantic analysis on function bodies.
- */
-
-void Dsymbol::semantic3(Scope *)
-{
- // Most Dsymbols have no further semantic analysis needed
-}
-
/*********************************************
* Search for ident as member of s.
* Params:
{
if (d->inuse)
{
- ::error(loc, "circular reference to '%s'", d->toPrettyChars());
+ ::error(loc, "circular reference to `%s`", d->toPrettyChars());
return NULL;
}
}
{
sm = s->search_correct(ti->name);
if (sm)
- ::error(loc, "template identifier '%s' is not a member of %s '%s', did you mean %s '%s'?",
+ ::error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?",
ti->name->toChars(), s->kind(), s->toPrettyChars(), sm->kind(), sm->toChars());
else
- ::error(loc, "template identifier '%s' is not a member of %s '%s'",
+ ::error(loc, "template identifier `%s` is not a member of %s `%s`",
ti->name->toChars(), s->kind(), s->toPrettyChars());
return NULL;
}
}
ti->tempdecl = td;
if (!ti->semanticRun)
- ti->semantic(sc);
+ dsymbolSemantic(ti, sc);
sm = ti->toAlias();
break;
}
d_uns64 Dsymbol::size(Loc)
{
- error("Dsymbol '%s' has no size", toChars());
+ error("Dsymbol `%s` has no size", toChars());
return SIZE_INVALID;
}
forward->importScope(s, protection);
}
-void ForwardingScopeDsymbol::semantic(Scope *)
-{
-}
-
const char *ForwardingScopeDsymbol::kind() const
{
return "local scope";
return sds;
}
-void ScopeDsymbol::semantic(Scope *)
-{
-}
-
/*****************************************
* This function is #1 on the list of functions that eat cpu time.
* Be very, very careful about slowing it down.
Expression *e = new IntegerExp(Loc(), td->objects->length, Type::tsize_t);
v->_init = new ExpInitializer(Loc(), e);
v->storage_class |= STCtemp | STCstatic | STCconst;
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
return v;
}
Expression *e = new IntegerExp(Loc(), type->arguments->length, Type::tsize_t);
v->_init = new ExpInitializer(Loc(), e);
v->storage_class |= STCtemp | STCstatic | STCconst;
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
return v;
}
Objects *tiargs = new Objects();
Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t);
- edim = ::semantic(edim, sc);
+ edim = expressionSemantic(edim, sc);
tiargs->push(edim);
e = new DotTemplateInstanceExp(loc, ce, td->ident, tiargs);
}
assert(d);
e = new DotVarExp(loc, ce, d);
}
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (!e->type)
exp->error("%s has no value", e->toChars());
t = e->type->toBasetype();
}
*pvar = v;
}
- (*pvar)->semantic(sc);
+ dsymbolSemantic(*pvar, sc);
return (*pvar);
}
return NULL;
/* 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.
~Ungag() { global.gag = oldgag; }
};
+void dsymbolSemantic(Dsymbol *dsym, Scope *sc);
+void semantic2(Dsymbol *dsym, Scope* sc);
+void semantic3(Dsymbol *dsym, Scope* sc);
+
struct Prot
{
enum Kind
virtual void addMember(Scope *sc, ScopeDsymbol *sds);
virtual void setScope(Scope *sc);
virtual void importAll(Scope *sc);
- virtual void semantic(Scope *sc);
- virtual void semantic2(Scope *sc);
- virtual void semantic3(Scope *sc);
virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
Dsymbol *search_correct(Identifier *id);
Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id);
static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL);
ScopeDsymbol *isScopeDsymbol() { return this; }
- void semantic(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
Dsymbol *symtabInsert(Dsymbol *s);
Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
void importScope(Dsymbol *s, Prot protection);
- void semantic(Scope *sc);
const char *kind() const;
ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; }
--- /dev/null
+
+/* 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);
+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());
+ }
+ }
+ 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 | 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);
+ }
+
+ // Mark the imported packages as accessible from the current
+ // scope. This access check is necessary when using FQN b/c
+ // we're using a single global package tree. See Bugzilla 313.
+ if (imp->packages)
+ {
+ // import a.b.c.d;
+ Package *p = imp->pkg; // a
+ scopesym->addAccessiblePackage(p, imp->protection);
+ for (size_t i = 1; i < imp->packages->length; i++) // [b, c]
+ {
+ Identifier *id = (*imp->packages)[i];
+ p = (Package *) p->symtab->lookup(id);
+ scopesym->addAccessiblePackage(p, imp->protection);
+ }
+ }
+ scopesym->addAccessiblePackage(imp->mod, imp->protection); // d
+ }
+
+ 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);
+ if (imp->mod->search(imp->loc, imp->names[i]))
+ {
+ 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->toChars());
+ 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();
+
+ // pragma(msg) is allowed to contain types as well as expressions
+ 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 (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());
+ StringExp *se = semanticString(sc, cd->exp, "argument to mixin");
+ if (!se)
+ return NULL;
+ se = se->toUTF8(sc);
+
+ unsigned errors = global.errors;
+ Parser p(cd->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+ p.nextToken();
+
+ Dsymbols *d = p.parseDeclDefs(0);
+ if (global.errors != errors)
+ return NULL;
+
+ if (p.token.value != TOKeof)
+ {
+ cd->exp->error("incomplete mixin declaration (%s)", se->toChars());
+ 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)
+ {
+ 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();
+ ed->_scope->_module->addDeferredSemantic(ed);
+ Module::dprogress = dprogress_save;
+ //printf("\tdeferring %s\n", ed->toChars());
+ ed->semanticRun = PASSinit;
+ return;
+ }
+ }
+ 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();
+ tm->_scope->_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;
+ }
+
+ void funcDeclarationSemantic(FuncDeclaration *funcdecl)
+ {
+ TypeFunction *f;
+ AggregateDeclaration *ad;
+ InterfaceDeclaration *id;
+
+ if (funcdecl->semanticRun != PASSinit && funcdecl->isFuncLiteralDeclaration())
+ {
+ /* Member functions that have return types that are
+ * forward references can have semantic() run more than
+ * once on them.
+ * See test\interface2.d, test20
+ */
+ return;
+ }
+
+ if (funcdecl->semanticRun >= PASSsemanticdone)
+ return;
+ assert(funcdecl->semanticRun <= PASSsemantic);
+ funcdecl->semanticRun = PASSsemantic;
+
+ if (funcdecl->_scope)
+ {
+ sc = funcdecl->_scope;
+ funcdecl->_scope = NULL;
+ }
+
+ if (!sc || funcdecl->errors)
+ return;
+
+ funcdecl->parent = sc->parent;
+ Dsymbol *parent = funcdecl->toParent();
+
+ funcdecl->foverrides.setDim(0); // reset in case semantic() is being retried for this function
+
+ funcdecl->storage_class |= sc->stc & ~STCref;
+ ad = funcdecl->isThis();
+ // Don't nest structs b/c of generated methods which should not access the outer scopes.
+ // https://issues.dlang.org/show_bug.cgi?id=16627
+ if (ad && !funcdecl->generated)
+ {
+ funcdecl->storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized);
+ ad->makeNested();
+ }
+ if (sc->func)
+ funcdecl->storage_class |= sc->func->storage_class & STCdisable;
+ // Remove prefix storage classes silently.
+ if ((funcdecl->storage_class & STC_TYPECTOR) && !(ad || funcdecl->isNested()))
+ funcdecl->storage_class &= ~STC_TYPECTOR;
+
+ //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", funcdecl->storage_class, sc->stc, Declaration::isFinal());
+
+ FuncLiteralDeclaration *fld = funcdecl->isFuncLiteralDeclaration();
+ if (fld && fld->treq)
+ {
+ Type *treq = fld->treq;
+ assert(treq->nextOf()->ty == Tfunction);
+ if (treq->ty == Tdelegate)
+ fld->tok = TOKdelegate;
+ else if (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)
+ fld->tok = TOKfunction;
+ else
+ assert(0);
+ funcdecl->linkage = treq->nextOf()->toTypeFunction()->linkage;
+ }
+ else
+ funcdecl->linkage = sc->linkage;
+ funcdecl->inlining = sc->inlining;
+ funcdecl->protection = sc->protection;
+ funcdecl->userAttribDecl = sc->userAttribDecl;
+
+ if (!funcdecl->originalType)
+ funcdecl->originalType = funcdecl->type->syntaxCopy();
+ if (funcdecl->type->ty != Tfunction)
+ {
+ if (funcdecl->type->ty != Terror)
+ {
+ funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars());
+ funcdecl->type = Type::terror;
+ }
+ funcdecl->errors = true;
+ return;
+ }
+ if (!funcdecl->type->deco)
+ {
+ sc = sc->push();
+ sc->stc |= funcdecl->storage_class & (STCdisable | STCdeprecated); // forward to function type
+ TypeFunction *tf = funcdecl->type->toTypeFunction();
+
+ if (sc->func)
+ {
+ /* If the nesting parent is pure without inference,
+ * then this function defaults to pure too.
+ *
+ * auto foo() pure {
+ * auto bar() {} // become a weak purity funciton
+ * class C { // nested class
+ * auto baz() {} // become a weak purity funciton
+ * }
+ *
+ * static auto boo() {} // typed as impure
+ * // Even though, boo cannot call any impure functions.
+ * // See also Expression::checkPurity().
+ * }
+ */
+ if (tf->purity == PUREimpure && (funcdecl->isNested() || funcdecl->isThis()))
+ {
+ FuncDeclaration *fd = NULL;
+ for (Dsymbol *p = funcdecl->toParent2(); p; p = p->toParent2())
+ {
+ if (AggregateDeclaration *adx = p->isAggregateDeclaration())
+ {
+ if (adx->isNested())
+ continue;
+ break;
+ }
+ if ((fd = p->isFuncDeclaration()) != NULL)
+ break;
+ }
+
+ /* If the parent's purity is inferred, then this function's purity needs
+ * to be inferred first.
+ */
+ if (fd && fd->isPureBypassingInference() >= PUREweak &&
+ !funcdecl->isInstantiated())
+ {
+ tf->purity = PUREfwdref; // default to pure
+ }
+ }
+ }
+
+ if (tf->isref) sc->stc |= STCref;
+ if (tf->isscope) sc->stc |= STCscope;
+ if (tf->isnothrow) sc->stc |= STCnothrow;
+ if (tf->isnogc) sc->stc |= STCnogc;
+ if (tf->isproperty) sc->stc |= STCproperty;
+ if (tf->purity == PUREfwdref) sc->stc |= STCpure;
+ if (tf->trust != TRUSTdefault)
+ sc->stc &= ~(STCsafe | STCsystem | STCtrusted);
+ if (tf->trust == TRUSTsafe) sc->stc |= STCsafe;
+ if (tf->trust == TRUSTsystem) sc->stc |= STCsystem;
+ if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted;
+
+ if (funcdecl->isCtorDeclaration())
+ {
+ sc->flags |= SCOPEctor;
+
+ Type *tret = ad->handleType();
+ assert(tret);
+ tret = tret->addStorageClass(funcdecl->storage_class | sc->stc);
+ tret = tret->addMod(funcdecl->type->mod);
+ tf->next = tret;
+
+ if (ad->isStructDeclaration())
+ sc->stc |= STCref;
+ }
+
+ // 'return' on a non-static class member function implies 'scope' as well
+ if (ad && ad->isClassDeclaration() && (tf->isreturn || sc->stc & STCreturn) && !(sc->stc & STCstatic))
+ sc->stc |= STCscope;
+
+ // If 'this' has no pointers, remove 'scope' as it has no meaning
+ if (sc->stc & STCscope && ad && ad->isStructDeclaration() && !ad->type->hasPointers())
+ {
+ sc->stc &= ~STCscope;
+ tf->isscope = false;
+ }
+
+ sc->linkage = funcdecl->linkage;
+
+ if (!tf->isNaked() && !(funcdecl->isThis() || funcdecl->isNested()))
+ {
+ OutBuffer buf;
+ MODtoBuffer(&buf, tf->mod);
+ funcdecl->error("without `this` cannot be %s", buf.peekChars());
+ tf->mod = 0; // remove qualifiers
+ }
+
+ /* Apply const, immutable, wild and shared storage class
+ * to the function type. Do this before type semantic.
+ */
+ StorageClass stc = funcdecl->storage_class;
+ if (funcdecl->type->isImmutable())
+ stc |= STCimmutable;
+ if (funcdecl->type->isConst())
+ stc |= STCconst;
+ if (funcdecl->type->isShared() || funcdecl->storage_class & STCsynchronized)
+ stc |= STCshared;
+ if (funcdecl->type->isWild())
+ stc |= STCwild;
+ switch (stc & STC_TYPECTOR)
+ {
+ case STCimmutable:
+ case STCimmutable | STCconst:
+ case STCimmutable | STCwild:
+ case STCimmutable | STCwild | STCconst:
+ case STCimmutable | STCshared:
+ case STCimmutable | STCshared | STCconst:
+ case STCimmutable | STCshared | STCwild:
+ case STCimmutable | STCshared | STCwild | STCconst:
+ // Don't use immutableOf(), as that will do a merge()
+ funcdecl->type = funcdecl->type->makeImmutable();
+ break;
+
+ case STCconst:
+ funcdecl->type = funcdecl->type->makeConst();
+ break;
+
+ case STCwild:
+ funcdecl->type = funcdecl->type->makeWild();
+ break;
+
+ case STCwild | STCconst:
+ funcdecl->type = funcdecl->type->makeWildConst();
+ break;
+
+ case STCshared:
+ funcdecl->type = funcdecl->type->makeShared();
+ break;
+
+ case STCshared | STCconst:
+ funcdecl->type = funcdecl->type->makeSharedConst();
+ break;
+
+ case STCshared | STCwild:
+ funcdecl->type = funcdecl->type->makeSharedWild();
+ break;
+
+ case STCshared | STCwild | STCconst:
+ funcdecl->type = funcdecl->type->makeSharedWildConst();
+ break;
+
+ case 0:
+ break;
+
+ default:
+ assert(0);
+ }
+
+ funcdecl->type = typeSemantic(funcdecl->type, funcdecl->loc, sc);
+ sc = sc->pop();
+ }
+ if (funcdecl->type->ty != Tfunction)
+ {
+ if (funcdecl->type->ty != Terror)
+ {
+ funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars());
+ funcdecl->type = Type::terror;
+ }
+ funcdecl->errors = true;
+ return;
+ }
+ else
+ {
+ // Merge back function attributes into 'originalType'.
+ // It's used for mangling, ddoc, and json output.
+ TypeFunction *tfo = funcdecl->originalType->toTypeFunction();
+ TypeFunction *tfx = funcdecl->type->toTypeFunction();
+ tfo->mod = tfx->mod;
+ tfo->isscope = tfx->isscope;
+ tfo->isscopeinferred = tfx->isscopeinferred;
+ tfo->isref = tfx->isref;
+ tfo->isnothrow = tfx->isnothrow;
+ tfo->isnogc = tfx->isnogc;
+ tfo->isproperty = tfx->isproperty;
+ tfo->purity = tfx->purity;
+ tfo->trust = tfx->trust;
+
+ funcdecl->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
+ }
+
+ f = (TypeFunction *)funcdecl->type;
+
+ if ((funcdecl->storage_class & STCauto) && !f->isref && !funcdecl->inferRetType)
+ funcdecl->error("storage class `auto` has no effect if return type is not inferred");
+ /* Functions can only be 'scope' if they have a 'this'
+ */
+ if (f->isscope && !funcdecl->isNested() && !ad)
+ {
+ funcdecl->error("functions cannot be scope");
+ }
+
+ if (f->isreturn && !funcdecl->needThis() && !funcdecl->isNested())
+ {
+ /* Non-static nested functions have a hidden 'this' pointer to which
+ * the 'return' applies
+ */
+ funcdecl->error("static member has no `this` to which `return` can apply");
+ }
+
+ if (funcdecl->isAbstract() && !funcdecl->isVirtual())
+ {
+ const char *sfunc;
+ if (funcdecl->isStatic())
+ sfunc = "static";
+ else if (funcdecl->protection.kind == Prot::private_ || funcdecl->protection.kind == Prot::package_)
+ sfunc = protectionToChars(funcdecl->protection.kind);
+ else
+ sfunc = "non-virtual";
+ funcdecl->error("%s functions cannot be abstract", sfunc);
+ }
+
+ if (funcdecl->isOverride() && !funcdecl->isVirtual())
+ {
+ Prot::Kind kind = funcdecl->prot().kind;
+ if ((kind == Prot::private_ || kind == Prot::package_) && funcdecl->isMember())
+ funcdecl->error("%s method is not virtual and cannot override", protectionToChars(kind));
+ else
+ funcdecl->error("cannot override a non-virtual function");
+ }
+
+ if (funcdecl->isAbstract() && funcdecl->isFinalFunc())
+ funcdecl->error("cannot be both final and abstract");
+
+ id = parent->isInterfaceDeclaration();
+ if (id)
+ {
+ funcdecl->storage_class |= STCabstract;
+
+ if (funcdecl->isCtorDeclaration() ||
+ funcdecl->isPostBlitDeclaration() ||
+ funcdecl->isDtorDeclaration() ||
+ funcdecl->isInvariantDeclaration() ||
+ funcdecl->isNewDeclaration() || funcdecl->isDelete())
+ funcdecl->error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id->toChars());
+ if (funcdecl->fbody && funcdecl->isVirtual())
+ funcdecl->error("function body only allowed in final functions in interface %s", id->toChars());
+ }
+
+ if (UnionDeclaration *ud = parent->isUnionDeclaration())
+ {
+ if (funcdecl->isPostBlitDeclaration() ||
+ funcdecl->isDtorDeclaration() ||
+ funcdecl->isInvariantDeclaration())
+ funcdecl->error("destructors, postblits and invariants are not allowed in union %s", ud->toChars());
+ }
+
+ if (parent->isStructDeclaration())
+ {
+ if (funcdecl->isCtorDeclaration())
+ {
+ goto Ldone;
+ }
+ }
+
+ if (ClassDeclaration *cd = parent->isClassDeclaration())
+ {
+ if (funcdecl->isCtorDeclaration())
+ {
+ goto Ldone;
+ }
+
+ if (funcdecl->storage_class & STCabstract)
+ cd->isabstract = ABSyes;
+
+ // if static function, do not put in vtbl[]
+ if (!funcdecl->isVirtual())
+ {
+ //printf("\tnot virtual\n");
+ goto Ldone;
+ }
+ // Suppress further errors if the return type is an error
+ if (funcdecl->type->nextOf() == Type::terror)
+ goto Ldone;
+
+ bool may_override = false;
+ for (size_t i = 0; i < cd->baseclasses->length; i++)
+ {
+ BaseClass *b = (*cd->baseclasses)[i];
+ ClassDeclaration *cbd = b->type->toBasetype()->isClassHandle();
+ if (!cbd)
+ continue;
+ for (size_t j = 0; j < cbd->vtbl.length; j++)
+ {
+ FuncDeclaration *f2 = cbd->vtbl[j]->isFuncDeclaration();
+ if (!f2 || f2->ident != funcdecl->ident)
+ continue;
+ if (cbd->parent && cbd->parent->isTemplateInstance())
+ {
+ if (!f2->functionSemantic())
+ goto Ldone;
+ }
+ may_override = true;
+ }
+ }
+ if (may_override && funcdecl->type->nextOf() == NULL)
+ {
+ /* If same name function exists in base class but 'this' is auto return,
+ * cannot find index of base class's vtbl[] to override.
+ */
+ funcdecl->error("return type inference is not supported if may override base class function");
+ }
+
+ /* Find index of existing function in base class's vtbl[] to override
+ * (the index will be the same as in cd's current vtbl[])
+ */
+ int vi = cd->baseClass ? funcdecl->findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length)
+ : -1;
+
+ bool doesoverride = false;
+ switch (vi)
+ {
+ case -1:
+ Lintro:
+ /* Didn't find one, so
+ * This is an 'introducing' function which gets a new
+ * slot in the vtbl[].
+ */
+
+ // Verify this doesn't override previous final function
+ if (cd->baseClass)
+ {
+ Dsymbol *s = cd->baseClass->search(funcdecl->loc, funcdecl->ident);
+ if (s)
+ {
+ FuncDeclaration *f2 = s->isFuncDeclaration();
+ if (f2)
+ {
+ f2 = f2->overloadExactMatch(funcdecl->type);
+ if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_)
+ funcdecl->error("cannot override final function %s", f2->toPrettyChars());
+ }
+ }
+ }
+
+ /* These quirky conditions mimic what VC++ appears to do
+ */
+ if (global.params.mscoff && cd->isCPPclass() &&
+ cd->baseClass && cd->baseClass->vtbl.length)
+ {
+ /* if overriding an interface function, then this is not
+ * introducing and don't put it in the class vtbl[]
+ */
+ funcdecl->interfaceVirtual = funcdecl->overrideInterface();
+ if (funcdecl->interfaceVirtual)
+ {
+ //printf("\tinterface function %s\n", funcdecl->toChars());
+ cd->vtblFinal.push(funcdecl);
+ goto Linterfaces;
+ }
+ }
+
+ if (funcdecl->isFinalFunc())
+ {
+ // Don't check here, as it may override an interface function
+ //if (funcdecl->isOverride())
+ //funcdecl->error("is marked as override, but does not override any function");
+ cd->vtblFinal.push(funcdecl);
+ }
+ else
+ {
+ //printf("\tintroducing function %s\n", funcdecl->toChars());
+ funcdecl->introducing = 1;
+ if (cd->isCPPclass() && target.cpp.reverseOverloads)
+ {
+ // with dmc, overloaded functions are grouped and in reverse order
+ funcdecl->vtblIndex = (int)cd->vtbl.length;
+ for (int i = 0; i < (int)cd->vtbl.length; i++)
+ {
+ if (cd->vtbl[i]->ident == funcdecl->ident && cd->vtbl[i]->parent == parent)
+ {
+ funcdecl->vtblIndex = (int)i;
+ break;
+ }
+ }
+ // shift all existing functions back
+ for (int i = (int)cd->vtbl.length; i > funcdecl->vtblIndex; i--)
+ {
+ FuncDeclaration *fd = cd->vtbl[i-1]->isFuncDeclaration();
+ assert(fd);
+ fd->vtblIndex++;
+ }
+ cd->vtbl.insert(funcdecl->vtblIndex, funcdecl);
+ }
+ else
+ {
+ // Append to end of vtbl[]
+ vi = (int)cd->vtbl.length;
+ cd->vtbl.push(funcdecl);
+ funcdecl->vtblIndex = vi;
+ }
+ }
+ break;
+
+ case -2:
+ // can't determine because of forward references
+ funcdecl->errors = true;
+ return;
+
+ default:
+ {
+ FuncDeclaration *fdv = cd->baseClass->vtbl[vi]->isFuncDeclaration();
+ FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration();
+ // This function is covariant with fdv
+
+ if (fdc == funcdecl)
+ {
+ doesoverride = true;
+ break;
+ }
+
+ if (fdc->toParent() == parent)
+ {
+ //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n",
+ // vi, funcdecl, funcdecl->toChars(), funcdecl->type->toChars(), funcdecl->loc.toChars(),
+ // fdc, fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(),
+ // fdv, fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars());
+
+ // fdc overrides fdv exactly, then this introduces new function.
+ if (fdc->type->mod == fdv->type->mod && funcdecl->type->mod != fdv->type->mod)
+ goto Lintro;
+ }
+
+ // This function overrides fdv
+ if (fdv->isFinalFunc())
+ funcdecl->error("cannot override final function %s", fdv->toPrettyChars());
+
+ if (!funcdecl->isOverride())
+ {
+ if (fdv->isFuture())
+ {
+ ::deprecation(funcdecl->loc, "@__future base class method %s is being overridden by %s; rename the latter",
+ fdv->toPrettyChars(), funcdecl->toPrettyChars());
+ // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[]
+ goto Lintro;
+ }
+ else
+ {
+ int vi2 = funcdecl->findVtblIndex(&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length, false);
+ if (vi2 < 0)
+ // https://issues.dlang.org/show_bug.cgi?id=17349
+ ::deprecation(funcdecl->loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute",
+ fdv->toPrettyChars(), funcdecl->toPrettyChars());
+ else
+ error(funcdecl->loc, "implicitly overriding base class method %s with %s deprecated; add `override` attribute",
+ fdv->toPrettyChars(), funcdecl->toPrettyChars());
+ }
+ }
+
+ doesoverride = true;
+ if (fdc->toParent() == parent)
+ {
+ // If both are mixins, or both are not, then error.
+ // If either is not, the one that is not overrides the other.
+ bool thismixin = funcdecl->parent->isClassDeclaration() != NULL;
+ bool fdcmixin = fdc->parent->isClassDeclaration() != NULL;
+ if (thismixin == fdcmixin)
+ {
+ funcdecl->error("multiple overrides of same function");
+ }
+ else if (!thismixin) // fdc overrides fdv
+ {
+ // this doesn't override any function
+ break;
+ }
+ }
+ cd->vtbl[vi] = funcdecl;
+ funcdecl->vtblIndex = vi;
+
+ /* Remember which functions this overrides
+ */
+ funcdecl->foverrides.push(fdv);
+
+ /* This works by whenever this function is called,
+ * it actually returns tintro, which gets dynamically
+ * cast to type. But we know that tintro is a base
+ * of type, so we could optimize it by not doing a
+ * dynamic cast, but just subtracting the isBaseOf()
+ * offset if the value is != null.
+ */
+
+ if (fdv->tintro)
+ funcdecl->tintro = fdv->tintro;
+ else if (!funcdecl->type->equals(fdv->type))
+ {
+ /* Only need to have a tintro if the vptr
+ * offsets differ
+ */
+ int offset;
+ if (fdv->type->nextOf()->isBaseOf(funcdecl->type->nextOf(), &offset))
+ {
+ funcdecl->tintro = fdv->type;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Go through all the interface bases.
+ * If this function is covariant with any members of those interface
+ * functions, set the tintro.
+ */
+ Linterfaces:
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ vi = funcdecl->findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.length);
+ switch (vi)
+ {
+ case -1:
+ break;
+
+ case -2:
+ // can't determine because of forward references
+ funcdecl->errors = true;
+ return;
+
+ default:
+ {
+ FuncDeclaration *fdv = (FuncDeclaration *)b->sym->vtbl[vi];
+ Type *ti = NULL;
+
+ /* Remember which functions this overrides
+ */
+ funcdecl->foverrides.push(fdv);
+
+ /* Should we really require 'override' when implementing
+ * an interface function?
+ */
+ //if (!funcdecl->isOverride())
+ //warning(funcdecl->loc, "overrides base class function %s, but is not marked with `override`", fdv->toPrettyChars());
+
+ if (fdv->tintro)
+ ti = fdv->tintro;
+ else if (!funcdecl->type->equals(fdv->type))
+ {
+ /* Only need to have a tintro if the vptr
+ * offsets differ
+ */
+ int offset;
+ if (fdv->type->nextOf()->isBaseOf(funcdecl->type->nextOf(), &offset))
+ {
+ ti = fdv->type;
+ }
+ }
+ if (ti)
+ {
+ if (funcdecl->tintro)
+ {
+ if (!funcdecl->tintro->nextOf()->equals(ti->nextOf()) &&
+ !funcdecl->tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) &&
+ !ti->nextOf()->isBaseOf(funcdecl->tintro->nextOf(), NULL))
+ {
+ funcdecl->error("incompatible covariant types %s and %s", funcdecl->tintro->toChars(), ti->toChars());
+ }
+ }
+ funcdecl->tintro = ti;
+ }
+ goto L2;
+ }
+ }
+ }
+
+ if (!doesoverride && funcdecl->isOverride() && (funcdecl->type->nextOf() || !may_override))
+ {
+ BaseClass *bc = NULL;
+ Dsymbol *s = NULL;
+ for (size_t i = 0; i < cd->baseclasses->length; i++)
+ {
+ bc = (*cd->baseclasses)[i];
+ s = bc->sym->search_correct(funcdecl->ident);
+ if (s) break;
+ }
+
+ if (s)
+ funcdecl->error("does not override any function, did you mean to override `%s%s`?",
+ bc->sym->isCPPclass() ? "extern (C++) " : "", s->toPrettyChars());
+ else
+ funcdecl->error("does not override any function");
+ }
+
+ L2: ;
+
+ /* Go through all the interface bases.
+ * Disallow overriding any final functions in the interface(s).
+ */
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ if (b->sym)
+ {
+ Dsymbol *s = search_function(b->sym, funcdecl->ident);
+ if (s)
+ {
+ FuncDeclaration *f2 = s->isFuncDeclaration();
+ if (f2)
+ {
+ f2 = f2->overloadExactMatch(funcdecl->type);
+ if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_)
+ funcdecl->error("cannot override final function %s.%s", b->sym->toChars(), f2->toPrettyChars());
+ }
+ }
+ }
+ }
+
+ if (funcdecl->isOverride())
+ {
+ if (funcdecl->storage_class & STCdisable)
+ funcdecl->deprecation("overridden functions cannot be annotated @disable");
+ if (funcdecl->isDeprecated())
+ funcdecl->deprecation("deprecated functions cannot be annotated @disable");
+ }
+ }
+ else if (funcdecl->isOverride() && !parent->isTemplateInstance())
+ funcdecl->error("override only applies to class member functions");
+
+ // Reflect this->type to f because it could be changed by findVtblIndex
+ f = funcdecl->type->toTypeFunction();
+
+ Ldone:
+ /* Contracts can only appear without a body when they are virtual interface functions
+ */
+ if (!funcdecl->fbody && !allowsContractWithoutBody(funcdecl))
+ funcdecl->error("in and out contracts can only appear without a body when they are virtual interface functions or abstract");
+
+ /* Do not allow template instances to add virtual functions
+ * to a class.
+ */
+ if (funcdecl->isVirtual())
+ {
+ TemplateInstance *ti = parent->isTemplateInstance();
+ if (ti)
+ {
+ // Take care of nested templates
+ while (1)
+ {
+ TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
+ if (!ti2)
+ break;
+ ti = ti2;
+ }
+
+ // If it's a member template
+ ClassDeclaration *cd = ti->tempdecl->isClassMember();
+ if (cd)
+ {
+ funcdecl->error("cannot use template to add virtual function to class `%s`", cd->toChars());
+ }
+ }
+ }
+
+ if (funcdecl->isMain())
+ funcdecl->checkDmain(); // Check main() parameters and return type
+
+ /* Purity and safety can be inferred for some functions by examining
+ * the function body.
+ */
+ if (canInferAttributes(funcdecl, sc))
+ initInferAttributes(funcdecl);
+
+ Module::dprogress++;
+ funcdecl->semanticRun = PASSsemanticdone;
+
+ /* Save scope for possible later use (if we need the
+ * function internals)
+ */
+ funcdecl->_scope = sc->copy();
+ funcdecl->_scope->setNoFree();
+
+ static bool printedMain = false; // semantic might run more than once
+ if (global.params.verbose && !printedMain)
+ {
+ const char *type = funcdecl->isMain() ? "main" : funcdecl->isWinMain() ? "winmain" : funcdecl->isDllMain() ? "dllmain" : (const char *)NULL;
+ Module *mod = sc->_module;
+
+ if (type && mod)
+ {
+ printedMain = true;
+ const char *name = mod->srcfile->toChars();
+ const char *path = FileName::searchPath(global.path, name, true);
+ message("entry %-10s\t%s", type, path ? path : name);
+ }
+ }
+
+ if (funcdecl->fbody && funcdecl->isMain() && sc->_module->isRoot())
+ Compiler::genCmain(sc);
+
+ assert(funcdecl->type->ty != Terror || funcdecl->errors);
+
+ // semantic for parameters' UDAs
+ const size_t nparams = f->parameterList.length();
+ for (size_t i = 0; i < nparams; i++)
+ {
+ Parameter *param = f->parameterList[i];
+ if (param && param->userAttribDecl)
+ dsymbolSemantic(param->userAttribDecl, sc);
+ }
+ }
+
+ // Do the semantic analysis on the external interface to the function.
+ void visit(FuncDeclaration *funcdecl)
+ {
+ funcDeclarationSemantic(funcdecl);
+ }
+
+ void visit(CtorDeclaration *ctd)
+ {
+ //printf("CtorDeclaration::semantic() %s\n", ctd->toChars());
+ if (ctd->semanticRun >= PASSsemanticdone)
+ return;
+ if (ctd->_scope)
+ {
+ sc = ctd->_scope;
+ ctd->_scope = NULL;
+ }
+
+ ctd->parent = sc->parent;
+ Dsymbol *p = ctd->toParent2();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ error(ctd->loc, "constructor can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ ctd->type = Type::terror;
+ ctd->errors = true;
+ return;
+ }
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not a static constructor
+ sc->flags |= SCOPEctor;
+
+ funcDeclarationSemantic(ctd);
+
+ sc->pop();
+
+ if (ctd->errors)
+ return;
+
+ TypeFunction *tf = ctd->type->toTypeFunction();
+
+ /* See if it's the default constructor
+ * But, template constructor should not become a default constructor.
+ */
+ if (ad && (!ctd->parent->isTemplateInstance() || ctd->parent->isTemplateMixin()))
+ {
+ const size_t dim = tf->parameterList.length();
+
+ if (StructDeclaration *sd = ad->isStructDeclaration())
+ {
+ if (dim == 0 && tf->parameterList.varargs == VARARGnone) // empty default ctor w/o any varargs
+ {
+ if (ctd->fbody || !(ctd->storage_class & STCdisable) || dim)
+ {
+ ctd->error("default constructor for structs only allowed "
+ "with @disable, no body, and no parameters");
+ ctd->storage_class |= STCdisable;
+ ctd->fbody = NULL;
+ }
+ sd->noDefaultCtor = true;
+ }
+ else if (dim == 0 && tf->parameterList.varargs) // allow varargs only ctor
+ {
+ }
+ else if (dim && tf->parameterList[0]->defaultArg)
+ {
+ // if the first parameter has a default argument, then the rest does as well
+ if (ctd->storage_class & STCdisable)
+ {
+ ctd->deprecation("@disable'd constructor cannot have default "
+ "arguments for all parameters.");
+ deprecationSupplemental(ctd->loc, "Use @disable this(); if you want to disable default initialization.");
+ }
+ else
+ ctd->deprecation("all parameters have default arguments, "
+ "but structs cannot have default constructors.");
+ }
+
+ }
+ else if (dim == 0 && tf->parameterList.varargs == VARARGnone)
+ {
+ ad->defaultCtor = ctd;
+ }
+ }
+ }
+
+ void visit(PostBlitDeclaration *pbd)
+ {
+ //printf("PostBlitDeclaration::semantic() %s\n", pbd->toChars());
+ //printf("ident: %s, %s, %p, %p\n", pbd->ident->toChars(), Id::dtor->toChars(), pbd->ident, Id::dtor);
+ //printf("stc = x%llx\n", sc->stc);
+ if (pbd->semanticRun >= PASSsemanticdone)
+ return;
+ if (pbd->_scope)
+ {
+ sc = pbd->_scope;
+ pbd->_scope = NULL;
+ }
+
+ pbd->parent = sc->parent;
+ Dsymbol *p = pbd->toParent2();
+ StructDeclaration *ad = p->isStructDeclaration();
+ if (!ad)
+ {
+ error(pbd->loc, "postblit can only be a member of struct/union, not %s %s",
+ p->kind(), p->toChars());
+ pbd->type = Type::terror;
+ pbd->errors = true;
+ return;
+ }
+ if (pbd->ident == Id::postblit && pbd->semanticRun < PASSsemantic)
+ ad->postblits.push(pbd);
+ if (!pbd->type)
+ pbd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, pbd->storage_class);
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not static
+ sc->linkage = LINKd;
+
+ funcDeclarationSemantic(pbd);
+
+ sc->pop();
+ }
+
+ void visit(DtorDeclaration *dd)
+ {
+ //printf("DtorDeclaration::semantic() %s\n", dd->toChars());
+ //printf("ident: %s, %s, %p, %p\n", dd->ident->toChars(), Id::dtor->toChars(), dd->ident, Id::dtor);
+ if (dd->semanticRun >= PASSsemanticdone)
+ return;
+ if (dd->_scope)
+ {
+ sc = dd->_scope;
+ dd->_scope = NULL;
+ }
+
+ dd->parent = sc->parent;
+ Dsymbol *p = dd->toParent2();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ error(dd->loc, "destructor can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ dd->type = Type::terror;
+ dd->errors = true;
+ return;
+ }
+ if (dd->ident == Id::dtor && dd->semanticRun < PASSsemantic)
+ ad->dtors.push(dd);
+ if (!dd->type)
+ dd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, dd->storage_class);
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not a static destructor
+ if (sc->linkage != LINKcpp)
+ sc->linkage = LINKd;
+
+ funcDeclarationSemantic(dd);
+
+ sc->pop();
+ }
+
+ void visit(StaticCtorDeclaration *scd)
+ {
+ //printf("StaticCtorDeclaration::semantic()\n");
+ if (scd->semanticRun >= PASSsemanticdone)
+ return;
+ if (scd->_scope)
+ {
+ sc = scd->_scope;
+ scd->_scope = NULL;
+ }
+
+ scd->parent = sc->parent;
+ Dsymbol *p = scd->parent->pastMixin();
+ if (!p->isScopeDsymbol())
+ {
+ const char *s = (scd->isSharedStaticCtorDeclaration() ? "shared " : "");
+ error(scd->loc, "%sstatic constructor can only be member of module/aggregate/template, not %s %s",
+ s, p->kind(), p->toChars());
+ scd->type = Type::terror;
+ scd->errors = true;
+ return;
+ }
+ if (!scd->type)
+ scd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, scd->storage_class);
+
+ /* If the static ctor appears within a template instantiation,
+ * it could get called multiple times by the module constructors
+ * for different modules. Thus, protect it with a gate.
+ */
+ if (scd->isInstantiated() && scd->semanticRun < PASSsemantic)
+ {
+ /* Add this prefix to the function:
+ * static int gate;
+ * if (++gate != 1) return;
+ * Note that this is not thread safe; should not have threads
+ * during static construction.
+ */
+ VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
+ v->storage_class = STCtemp | (scd->isSharedStaticCtorDeclaration() ? STCstatic : STCtls);
+ Statements *sa = new Statements();
+ Statement *s = new ExpStatement(Loc(), v);
+ sa->push(s);
+ Expression *e = new IdentifierExp(Loc(), v->ident);
+ e = new AddAssignExp(Loc(), e, new IntegerExp(1));
+ e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(1));
+ s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
+ sa->push(s);
+ if (scd->fbody)
+ sa->push(scd->fbody);
+ scd->fbody = new CompoundStatement(Loc(), sa);
+ }
+
+ funcDeclarationSemantic(scd);
+
+ // We're going to need ModuleInfo
+ Module *m = scd->getModule();
+ if (!m)
+ m = sc->_module;
+ if (m)
+ {
+ m->needmoduleinfo = 1;
+ //printf("module1 %s needs moduleinfo\n", m->toChars());
+ }
+ }
+
+ void visit(StaticDtorDeclaration *sdd)
+ {
+ if (sdd->semanticRun >= PASSsemanticdone)
+ return;
+ if (sdd->_scope)
+ {
+ sc = sdd->_scope;
+ sdd->_scope = NULL;
+ }
+
+ sdd->parent = sc->parent;
+ Dsymbol *p = sdd->parent->pastMixin();
+ if (!p->isScopeDsymbol())
+ {
+ const char *s = (sdd->isSharedStaticDtorDeclaration() ? "shared " : "");
+ error(sdd->loc, "%sstatic destructor can only be member of module/aggregate/template, not %s %s",
+ s, p->kind(), p->toChars());
+ sdd->type = Type::terror;
+ sdd->errors = true;
+ return;
+ }
+ if (!sdd->type)
+ sdd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, sdd->storage_class);
+
+ /* If the static ctor appears within a template instantiation,
+ * it could get called multiple times by the module constructors
+ * for different modules. Thus, protect it with a gate.
+ */
+ if (sdd->isInstantiated() && sdd->semanticRun < PASSsemantic)
+ {
+ /* Add this prefix to the function:
+ * static int gate;
+ * if (--gate != 0) return;
+ * Increment gate during constructor execution.
+ * Note that this is not thread safe; should not have threads
+ * during static destruction.
+ */
+ VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
+ v->storage_class = STCtemp | (sdd->isSharedStaticDtorDeclaration() ? STCstatic : STCtls);
+ Statements *sa = new Statements();
+ Statement *s = new ExpStatement(Loc(), v);
+ sa->push(s);
+ Expression *e = new IdentifierExp(Loc(), v->ident);
+ e = new AddAssignExp(Loc(), e, new IntegerExp(-1));
+ e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(0));
+ s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
+ sa->push(s);
+ if (sdd->fbody)
+ sa->push(sdd->fbody);
+ sdd->fbody = new CompoundStatement(Loc(), sa);
+ sdd->vgate = v;
+ }
+
+ funcDeclarationSemantic(sdd);
+
+ // We're going to need ModuleInfo
+ Module *m = sdd->getModule();
+ if (!m)
+ m = sc->_module;
+ if (m)
+ {
+ m->needmoduleinfo = 1;
+ //printf("module2 %s needs moduleinfo\n", m->toChars());
+ }
+ }
+
+ void visit(InvariantDeclaration *invd)
+ {
+ if (invd->semanticRun >= PASSsemanticdone)
+ return;
+ if (invd->_scope)
+ {
+ sc = invd->_scope;
+ invd->_scope = NULL;
+ }
+
+ invd->parent = sc->parent;
+ Dsymbol *p = invd->parent->pastMixin();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ error(invd->loc, "invariant can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ invd->type = Type::terror;
+ invd->errors = true;
+ return;
+ }
+ if (invd->ident != Id::classInvariant &&
+ invd->semanticRun < PASSsemantic &&
+ !ad->isUnionDeclaration() // users are on their own with union fields
+ )
+ ad->invs.push(invd);
+ if (!invd->type)
+ invd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, invd->storage_class);
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not a static invariant
+ sc->stc |= STCconst; // invariant() is always const
+ sc->flags = (sc->flags & ~SCOPEcontract) | SCOPEinvariant;
+ sc->linkage = LINKd;
+
+ funcDeclarationSemantic(invd);
+
+ sc->pop();
+ }
+
+ void visit(UnitTestDeclaration *utd)
+ {
+ if (utd->semanticRun >= PASSsemanticdone)
+ return;
+ if (utd->_scope)
+ {
+ sc = utd->_scope;
+ utd->_scope = NULL;
+ }
+
+ utd->protection = sc->protection;
+
+ utd->parent = sc->parent;
+ Dsymbol *p = utd->parent->pastMixin();
+ if (!p->isScopeDsymbol())
+ {
+ error(utd->loc, "unittest can only be a member of module/aggregate/template, not %s %s",
+ p->kind(), p->toChars());
+ utd->type = Type::terror;
+ utd->errors = true;
+ return;
+ }
+
+ if (global.params.useUnitTests)
+ {
+ if (!utd->type)
+ utd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, utd->storage_class);
+ Scope *sc2 = sc->push();
+ sc2->linkage = LINKd;
+ funcDeclarationSemantic(utd);
+ sc2->pop();
+ }
+ }
+
+ void visit(NewDeclaration *nd)
+ {
+ //printf("NewDeclaration::semantic()\n");
+ if (nd->semanticRun >= PASSsemanticdone)
+ return;
+ if (nd->_scope)
+ {
+ sc = nd->_scope;
+ nd->_scope = NULL;
+ }
+
+ nd->parent = sc->parent;
+ Dsymbol *p = nd->parent->pastMixin();
+ if (!p->isAggregateDeclaration())
+ {
+ error(nd->loc, "allocator can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ nd->type = Type::terror;
+ nd->errors = true;
+ return;
+ }
+ Type *tret = Type::tvoid->pointerTo();
+ if (!nd->type)
+ nd->type = new TypeFunction(ParameterList(nd->parameters, nd->varargs), tret, LINKd, nd->storage_class);
+
+ nd->type = typeSemantic(nd->type, nd->loc, sc);
+
+ // Check that there is at least one argument of type size_t
+ TypeFunction *tf = nd->type->toTypeFunction();
+ if (tf->parameterList.length() < 1)
+ {
+ nd->error("at least one argument of type size_t expected");
+ }
+ else
+ {
+ Parameter *fparam = tf->parameterList[0];
+ if (!fparam->type->equals(Type::tsize_t))
+ nd->error("first argument must be type size_t, not %s", fparam->type->toChars());
+ }
+
+ funcDeclarationSemantic(nd);
+ }
+
+ void visit(DeleteDeclaration *deld)
+ {
+ //printf("DeleteDeclaration::semantic()\n");
+ if (deld->semanticRun >= PASSsemanticdone)
+ return;
+ if (deld->_scope)
+ {
+ sc = deld->_scope;
+ deld->_scope = NULL;
+ }
+
+ deld->parent = sc->parent;
+ Dsymbol *p = deld->parent->pastMixin();
+ if (!p->isAggregateDeclaration())
+ {
+ error(deld->loc, "deallocator can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ deld->type = Type::terror;
+ deld->errors = true;
+ return;
+ }
+ if (!deld->type)
+ deld->type = new TypeFunction(ParameterList(deld->parameters), Type::tvoid, LINKd, deld->storage_class);
+
+ deld->type = typeSemantic(deld->type, deld->loc, sc);
+
+ // Check that there is only one argument of type void*
+ TypeFunction *tf = deld->type->toTypeFunction();
+ if (tf->parameterList.length() != 1)
+ {
+ deld->error("one argument of type void* expected");
+ }
+ else
+ {
+ Parameter *fparam = tf->parameterList[0];
+ if (!fparam->type->equals(Type::tvoid->pointerTo()))
+ deld->error("one argument of type void* expected, not %s", fparam->type->toChars());
+ }
+
+ funcDeclarationSemantic(deld);
+ }
+
+ void visit(StructDeclaration *sd)
+ {
+ //printf("StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", sd, sd->parent->toChars(), sd->toChars(), sizeok);
+
+ //static int count; if (++count == 20) halt();
+
+ if (sd->semanticRun >= PASSsemanticdone)
+ return;
+ unsigned errors = global.errors;
+
+ //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", sd, sd->parent->toChars(), sd->toChars(), sizeok);
+ Scope *scx = NULL;
+ if (sd->_scope)
+ {
+ sc = sd->_scope;
+ scx = sd->_scope; // save so we don't make redundant copies
+ sd->_scope = NULL;
+ }
+
+ if (!sd->parent)
+ {
+ assert(sc->parent && sc->func);
+ sd->parent = sc->parent;
+ }
+ assert(sd->parent && !sd->isAnonymous());
+
+ if (sd->errors)
+ sd->type = Type::terror;
+ if (sd->semanticRun == PASSinit)
+ sd->type = sd->type->addSTC(sc->stc | sd->storage_class);
+ sd->type = typeSemantic(sd->type, sd->loc, sc);
+
+ if (sd->type->ty == Tstruct && ((TypeStruct *)sd->type)->sym != sd)
+ {
+ TemplateInstance *ti = ((TypeStruct *)sd->type)->sym->isInstantiated();
+ if (ti && isError(ti))
+ ((TypeStruct *)sd->type)->sym = sd;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = sd->ungagSpeculative();
+
+ if (sd->semanticRun == PASSinit)
+ {
+ sd->protection = sc->protection;
+
+ sd->alignment = sc->alignment();
+
+ sd->storage_class |= sc->stc;
+ if (sd->storage_class & STCdeprecated)
+ sd->isdeprecated = true;
+ if (sd->storage_class & STCabstract)
+ sd->error("structs, unions cannot be abstract");
+ sd->userAttribDecl = sc->userAttribDecl;
+
+ if (sc->linkage == LINKcpp)
+ sd->classKind = ClassKind::cpp;
+ }
+ else if (sd->symtab && !scx)
+ {
+ return;
+ }
+ sd->semanticRun = PASSsemantic;
+
+ if (!sd->members) // if opaque declaration
+ {
+ sd->semanticRun = PASSsemanticdone;
+ return;
+ }
+ if (!sd->symtab)
+ {
+ sd->symtab = new DsymbolTable();
+
+ for (size_t i = 0; i < sd->members->length; i++)
+ {
+ Dsymbol *s = (*sd->members)[i];
+ //printf("adding member '%s' to '%s'\n", s->toChars(), sd->toChars());
+ s->addMember(sc, sd);
+ }
+ }
+
+ Scope *sc2 = sd->newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ for (size_t i = 0; i < sd->members->length; i++)
+ {
+ Dsymbol *s = (*sd->members)[i];
+ //printf("struct: setScope %s %s\n", s->kind(), s->toChars());
+ s->setScope(sc2);
+ }
+
+ for (size_t i = 0; i < sd->members->length; i++)
+ {
+ Dsymbol *s = (*sd->members)[i];
+ s->importAll(sc2);
+ }
+
+ for (size_t i = 0; i < sd->members->length; i++)
+ {
+ Dsymbol *s = (*sd->members)[i];
+ dsymbolSemantic(s, sc2);
+ }
+
+ if (!sd->determineFields())
+ {
+ assert(sd->type->ty == Terror);
+ sc2->pop();
+ sd->semanticRun = PASSsemanticdone;
+ return;
+ }
+
+ /* Following special member functions creation needs semantic analysis
+ * completion of sub-structs in each field types. For example, buildDtor
+ * needs to check existence of elaborate dtor in type of each fields.
+ * See the case in compilable/test14838.d
+ */
+ for (size_t i = 0; i < sd->fields.length; i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ Type *tb = v->type->baseElemOf();
+ if (tb->ty != Tstruct)
+ continue;
+ StructDeclaration *sdec = ((TypeStruct *)tb)->sym;
+ if (sdec->semanticRun >= PASSsemanticdone)
+ continue;
+
+ sc2->pop();
+
+ sd->_scope = scx ? scx : sc->copy();
+ sd->_scope->setNoFree();
+ sd->_scope->_module->addDeferredSemantic(sd);
+
+ //printf("\tdeferring %s\n", sd->toChars());
+ return;
+ }
+
+ /* Look for special member functions.
+ */
+ sd->aggNew = (NewDeclaration *)sd->search(Loc(), Id::classNew);
+ sd->aggDelete = (DeleteDeclaration *)sd->search(Loc(), Id::classDelete);
+
+ // Look for the constructor
+ sd->ctor = sd->searchCtor();
+
+ sd->dtor = buildDtor(sd, sc2);
+ sd->postblit = buildPostBlit(sd, sc2);
+
+ buildOpAssign(sd, sc2);
+ buildOpEquals(sd, sc2);
+
+ if (global.params.useTypeInfo && Type::dtypeinfo) // these functions are used for TypeInfo
+ {
+ sd->xeq = buildXopEquals(sd, sc2);
+ sd->xcmp = buildXopCmp(sd, sc2);
+ sd->xhash = buildXtoHash(sd, sc2);
+ }
+
+ sd->inv = buildInv(sd, sc2);
+
+ Module::dprogress++;
+ sd->semanticRun = PASSsemanticdone;
+ //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd->toChars());
+
+ sc2->pop();
+
+ if (sd->ctor)
+ {
+ Dsymbol *scall = sd->search(Loc(), Id::call);
+ if (scall)
+ {
+ unsigned xerrors = global.startGagging();
+ sc = sc->push();
+ sc->tinst = NULL;
+ sc->minst = NULL;
+ FuncDeclaration *fcall = resolveFuncCall(sd->loc, sc, scall, NULL, NULL, NULL, 1);
+ sc = sc->pop();
+ global.endGagging(xerrors);
+
+ if (fcall && fcall->isStatic())
+ {
+ sd->error(fcall->loc, "`static opCall` is hidden by constructors and can never be called");
+ errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with `static opCall`.");
+ }
+ }
+ }
+
+ if (sd->type->ty == Tstruct && ((TypeStruct *)sd->type)->sym != sd)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=19024
+ StructDeclaration *sym = ((TypeStruct *)sd->type)->sym;
+ sd->error("already exists at %s. Perhaps in another function with the same name?", sym->loc.toChars());
+ }
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ sd->type = Type::terror;
+ sd->errors = true;
+ if (sd->deferred)
+ sd->deferred->errors = true;
+ }
+
+ if (sd->deferred && !global.gag)
+ {
+ semantic2(sd->deferred, sc);
+ semantic3(sd->deferred, sc);
+ }
+ }
+
+ void interfaceSemantic(ClassDeclaration *cd)
+ {
+ cd->vtblInterfaces = new BaseClasses();
+ cd->vtblInterfaces->reserve(cd->interfaces.length);
+
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ cd->vtblInterfaces->push(b);
+ b->copyBaseInterfaces(cd->vtblInterfaces);
+ }
+ }
+
+ void visit(ClassDeclaration *cldec)
+ {
+ //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec);
+ //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
+ //printf("sc->stc = %x\n", sc->stc);
+
+ //{ static int n; if (++n == 20) *(char*)0=0; }
+
+ if (cldec->semanticRun >= PASSsemanticdone)
+ return;
+ unsigned errors = global.errors;
+
+ //printf("+ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec);
+
+ Scope *scx = NULL;
+ if (cldec->_scope)
+ {
+ sc = cldec->_scope;
+ scx = cldec->_scope; // save so we don't make redundant copies
+ cldec->_scope = NULL;
+ }
+
+ if (!cldec->parent)
+ {
+ assert(sc->parent);
+ cldec->parent = sc->parent;
+ }
+
+ if (cldec->errors)
+ cldec->type = Type::terror;
+ cldec->type = typeSemantic(cldec->type, cldec->loc, sc);
+
+ if (cldec->type->ty == Tclass && ((TypeClass *)cldec->type)->sym != cldec)
+ {
+ TemplateInstance *ti = ((TypeClass *)cldec->type)->sym->isInstantiated();
+ if (ti && isError(ti))
+ ((TypeClass *)cldec->type)->sym = cldec;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = cldec->ungagSpeculative();
+
+ if (cldec->semanticRun == PASSinit)
+ {
+ cldec->protection = sc->protection;
+
+ cldec->storage_class |= sc->stc;
+ if (cldec->storage_class & STCdeprecated)
+ cldec->isdeprecated = true;
+ if (cldec->storage_class & STCauto)
+ cldec->error("storage class `auto` is invalid when declaring a class, did you mean to use `scope`?");
+ if (cldec->storage_class & STCscope)
+ cldec->isscope = true;
+ if (cldec->storage_class & STCabstract)
+ cldec->isabstract = ABSyes;
+
+ cldec->userAttribDecl = sc->userAttribDecl;
+
+ if (sc->linkage == LINKcpp)
+ cldec->classKind = ClassKind::cpp;
+ if (sc->linkage == LINKobjc)
+ objc()->setObjc(cldec);
+ }
+ else if (cldec->symtab && !scx)
+ {
+ return;
+ }
+ cldec->semanticRun = PASSsemantic;
+
+ if (cldec->baseok < BASEOKdone)
+ {
+ cldec->baseok = BASEOKin;
+
+ // Expand any tuples in baseclasses[]
+ for (size_t i = 0; i < cldec->baseclasses->length; )
+ {
+ BaseClass *b = (*cldec->baseclasses)[i];
+ b->type = resolveBase(cldec, sc, scx, b->type);
+
+ Type *tb = b->type->toBasetype();
+ if (tb->ty == Ttuple)
+ {
+ TypeTuple *tup = (TypeTuple *)tb;
+ cldec->baseclasses->remove(i);
+ size_t dim = Parameter::dim(tup->arguments);
+ for (size_t j = 0; j < dim; j++)
+ {
+ Parameter *arg = Parameter::getNth(tup->arguments, j);
+ b = new BaseClass(arg->type);
+ cldec->baseclasses->insert(i + j, b);
+ }
+ }
+ else
+ i++;
+ }
+
+ if (cldec->baseok >= BASEOKdone)
+ {
+ //printf("%s already semantic analyzed, semanticRun = %d\n", cldec->toChars(), cldec->semanticRun);
+ if (cldec->semanticRun >= PASSsemanticdone)
+ return;
+ goto Lancestorsdone;
+ }
+
+ // See if there's a base class as first in baseclasses[]
+ if (cldec->baseclasses->length)
+ {
+ BaseClass *b = (*cldec->baseclasses)[0];
+ Type *tb = b->type->toBasetype();
+ TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+ if (!tc)
+ {
+ if (b->type != Type::terror)
+ cldec->error("base type must be class or interface, not %s", b->type->toChars());
+ cldec->baseclasses->remove(0);
+ goto L7;
+ }
+
+ if (tc->sym->isDeprecated())
+ {
+ if (!cldec->isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ cldec->isdeprecated = true;
+
+ tc->checkDeprecated(cldec->loc, sc);
+ }
+ }
+
+ if (tc->sym->isInterfaceDeclaration())
+ goto L7;
+
+ for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
+ {
+ if (cdb == cldec)
+ {
+ cldec->error("circular inheritance");
+ cldec->baseclasses->remove(0);
+ goto L7;
+ }
+ }
+
+ /* Bugzilla 11034: Essentially, class inheritance hierarchy
+ * and instance size of each classes are orthogonal information.
+ * Therefore, even if tc->sym->sizeof == SIZEOKnone,
+ * we need to set baseClass field for class covariance check.
+ */
+ cldec->baseClass = tc->sym;
+ b->sym = cldec->baseClass;
+
+ if (tc->sym->baseok < BASEOKdone)
+ resolveBase(cldec, sc, scx, tc->sym); // Try to resolve forward reference
+ if (tc->sym->baseok < BASEOKdone)
+ {
+ //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ cldec->baseok = BASEOKnone;
+ }
+ L7: ;
+ }
+
+ // Treat the remaining entries in baseclasses as interfaces
+ // Check for errors, handle forward references
+ for (size_t i = (cldec->baseClass ? 1 : 0); i < cldec->baseclasses->length; )
+ {
+ BaseClass *b = (*cldec->baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+ if (!tc || !tc->sym->isInterfaceDeclaration())
+ {
+ if (b->type != Type::terror)
+ cldec->error("base type must be interface, not %s", b->type->toChars());
+ cldec->baseclasses->remove(i);
+ continue;
+ }
+
+ // Check for duplicate interfaces
+ for (size_t j = (cldec->baseClass ? 1 : 0); j < i; j++)
+ {
+ BaseClass *b2 = (*cldec->baseclasses)[j];
+ if (b2->sym == tc->sym)
+ {
+ cldec->error("inherits from duplicate interface %s", b2->sym->toChars());
+ cldec->baseclasses->remove(i);
+ continue;
+ }
+ }
+
+ if (tc->sym->isDeprecated())
+ {
+ if (!cldec->isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ cldec->isdeprecated = true;
+
+ tc->checkDeprecated(cldec->loc, sc);
+ }
+ }
+
+ b->sym = tc->sym;
+
+ if (tc->sym->baseok < BASEOKdone)
+ resolveBase(cldec, sc, scx, tc->sym); // Try to resolve forward reference
+ if (tc->sym->baseok < BASEOKdone)
+ {
+ //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ cldec->baseok = BASEOKnone;
+ }
+ i++;
+ }
+ if (cldec->baseok == BASEOKnone)
+ {
+ // Forward referencee of one or more bases, try again later
+ cldec->_scope = scx ? scx : sc->copy();
+ cldec->_scope->setNoFree();
+ cldec->_scope->_module->addDeferredSemantic(cldec);
+ //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
+ return;
+ }
+ cldec->baseok = BASEOKdone;
+
+ // If no base class, and this is not an Object, use Object as base class
+ if (!cldec->baseClass && cldec->ident != Id::Object && !cldec->isCPPclass())
+ {
+ if (!ClassDeclaration::object || ClassDeclaration::object->errors)
+ badObjectDotD(cldec);
+
+ Type *t = ClassDeclaration::object->type;
+ t = typeSemantic(t, cldec->loc, sc)->toBasetype();
+ if (t->ty == Terror)
+ badObjectDotD(cldec);
+ assert(t->ty == Tclass);
+ TypeClass *tc = (TypeClass *)t;
+
+ BaseClass *b = new BaseClass(tc);
+ cldec->baseclasses->shift(b);
+
+ cldec->baseClass = tc->sym;
+ assert(!cldec->baseClass->isInterfaceDeclaration());
+ b->sym = cldec->baseClass;
+ }
+ if (cldec->baseClass)
+ {
+ if (cldec->baseClass->storage_class & STCfinal)
+ cldec->error("cannot inherit from final class %s", cldec->baseClass->toChars());
+
+ // Inherit properties from base class
+ if (cldec->baseClass->isCOMclass())
+ cldec->com = true;
+ if (cldec->baseClass->isCPPclass())
+ cldec->classKind = ClassKind::cpp;
+ if (cldec->baseClass->isscope)
+ cldec->isscope = true;
+ cldec->enclosing = cldec->baseClass->enclosing;
+ cldec->storage_class |= cldec->baseClass->storage_class & STC_TYPECTOR;
+ }
+
+ cldec->interfaces.length = cldec->baseclasses->length - (cldec->baseClass ? 1 : 0);
+ cldec->interfaces.ptr = cldec->baseclasses->tdata() + (cldec->baseClass ? 1 : 0);
+
+ for (size_t i = 0; i < cldec->interfaces.length; i++)
+ {
+ BaseClass *b = cldec->interfaces.ptr[i];
+ // If this is an interface, and it derives from a COM interface,
+ // then this is a COM interface too.
+ if (b->sym->isCOMinterface())
+ cldec->com = true;
+ if (cldec->isCPPclass() && !b->sym->isCPPinterface())
+ {
+ error(cldec->loc, "C++ class `%s` cannot implement D interface `%s`",
+ cldec->toPrettyChars(), b->sym->toPrettyChars());
+ }
+ }
+
+ interfaceSemantic(cldec);
+ }
+ Lancestorsdone:
+ //printf("\tClassDeclaration::semantic(%s) baseok = %d\n", cldec->toChars(), cldec->baseok);
+
+ if (!cldec->members) // if opaque declaration
+ {
+ cldec->semanticRun = PASSsemanticdone;
+ return;
+ }
+ if (!cldec->symtab)
+ {
+ cldec->symtab = new DsymbolTable();
+
+ /* Bugzilla 12152: The semantic analysis of base classes should be finished
+ * before the members semantic analysis of this class, in order to determine
+ * vtbl in this class. However if a base class refers the member of this class,
+ * it can be resolved as a normal forward reference.
+ * Call addMember() and setScope() to make this class members visible from the base classes.
+ */
+ for (size_t i = 0; i < cldec->members->length; i++)
+ {
+ Dsymbol *s = (*cldec->members)[i];
+ s->addMember(sc, cldec);
+ }
+
+ Scope *sc2 = cldec->newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ for (size_t i = 0; i < cldec->members->length; i++)
+ {
+ Dsymbol *s = (*cldec->members)[i];
+ //printf("[%d] setScope %s %s, sc2 = %p\n", i, s->kind(), s->toChars(), sc2);
+ s->setScope(sc2);
+ }
+
+ sc2->pop();
+ }
+
+ for (size_t i = 0; i < cldec->baseclasses->length; i++)
+ {
+ BaseClass *b = (*cldec->baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ assert(tb->ty == Tclass);
+ TypeClass *tc = (TypeClass *)tb;
+
+ if (tc->sym->semanticRun < PASSsemanticdone)
+ {
+ // Forward referencee of one or more bases, try again later
+ cldec->_scope = scx ? scx : sc->copy();
+ cldec->_scope->setNoFree();
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ cldec->_scope->_module->addDeferredSemantic(cldec);
+ //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
+ return;
+ }
+ }
+
+ if (cldec->baseok == BASEOKdone)
+ {
+ cldec->baseok = BASEOKsemanticdone;
+
+ // initialize vtbl
+ if (cldec->baseClass)
+ {
+ if (cldec->isCPPclass() && cldec->baseClass->vtbl.length == 0)
+ {
+ cldec->error("C++ base class %s needs at least one virtual function", cldec->baseClass->toChars());
+ }
+
+ // Copy vtbl[] from base class
+ cldec->vtbl.setDim(cldec->baseClass->vtbl.length);
+ memcpy(cldec->vtbl.tdata(), cldec->baseClass->vtbl.tdata(), sizeof(void *) * cldec->vtbl.length);
+
+ cldec->vthis = cldec->baseClass->vthis;
+ }
+ else
+ {
+ // No base class, so this is the root of the class hierarchy
+ cldec->vtbl.setDim(0);
+ if (cldec->vtblOffset())
+ cldec->vtbl.push(cldec); // leave room for classinfo as first member
+ }
+
+ /* If this is a nested class, add the hidden 'this'
+ * member which is a pointer to the enclosing scope.
+ */
+ if (cldec->vthis) // if inheriting from nested class
+ {
+ // Use the base class's 'this' member
+ if (cldec->storage_class & STCstatic)
+ cldec->error("static class cannot inherit from nested class %s", cldec->baseClass->toChars());
+ if (cldec->toParent2() != cldec->baseClass->toParent2() &&
+ (!cldec->toParent2() ||
+ !cldec->baseClass->toParent2()->getType() ||
+ !cldec->baseClass->toParent2()->getType()->isBaseOf(cldec->toParent2()->getType(), NULL)))
+ {
+ if (cldec->toParent2())
+ {
+ cldec->error("is nested within %s, but super class %s is nested within %s",
+ cldec->toParent2()->toChars(),
+ cldec->baseClass->toChars(),
+ cldec->baseClass->toParent2()->toChars());
+ }
+ else
+ {
+ cldec->error("is not nested, but super class %s is nested within %s",
+ cldec->baseClass->toChars(),
+ cldec->baseClass->toParent2()->toChars());
+ }
+ cldec->enclosing = NULL;
+ }
+ }
+ else
+ cldec->makeNested();
+ }
+
+ Scope *sc2 = cldec->newScope(sc);
+
+ for (size_t i = 0; i < cldec->members->length; i++)
+ {
+ Dsymbol *s = (*cldec->members)[i];
+ s->importAll(sc2);
+ }
+
+ // Note that members.length can grow due to tuple expansion during semantic()
+ for (size_t i = 0; i < cldec->members->length; i++)
+ {
+ Dsymbol *s = (*cldec->members)[i];
+ dsymbolSemantic(s, sc2);
+ }
+
+ if (!cldec->determineFields())
+ {
+ assert(cldec->type == Type::terror);
+ sc2->pop();
+ return;
+ }
+
+ /* Following special member functions creation needs semantic analysis
+ * completion of sub-structs in each field types.
+ */
+ for (size_t i = 0; i < cldec->fields.length; i++)
+ {
+ VarDeclaration *v = cldec->fields[i];
+ Type *tb = v->type->baseElemOf();
+ if (tb->ty != Tstruct)
+ continue;
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ if (sd->semanticRun >= PASSsemanticdone)
+ continue;
+
+ sc2->pop();
+
+ cldec->_scope = scx ? scx : sc->copy();
+ cldec->_scope->setNoFree();
+ cldec->_scope->_module->addDeferredSemantic(cldec);
+ //printf("\tdeferring %s\n", cldec->toChars());
+ return;
+ }
+
+ /* Look for special member functions.
+ * They must be in this class, not in a base class.
+ */
+
+ // Can be in base class
+ cldec->aggNew = (NewDeclaration *)cldec->search(Loc(), Id::classNew);
+ cldec->aggDelete = (DeleteDeclaration *)cldec->search(Loc(), Id::classDelete);
+
+ // Look for the constructor
+ cldec->ctor = cldec->searchCtor();
+
+ if (!cldec->ctor && cldec->noDefaultCtor)
+ {
+ // A class object is always created by constructor, so this check is legitimate.
+ for (size_t i = 0; i < cldec->fields.length; i++)
+ {
+ VarDeclaration *v = cldec->fields[i];
+ if (v->storage_class & STCnodefaultctor)
+ error(v->loc, "field %s must be initialized in constructor", v->toChars());
+ }
+ }
+
+ // If this class has no constructor, but base class has a default
+ // ctor, create a constructor:
+ // this() { }
+ if (!cldec->ctor && cldec->baseClass && cldec->baseClass->ctor)
+ {
+ FuncDeclaration *fd = resolveFuncCall(cldec->loc, sc2, cldec->baseClass->ctor, NULL, cldec->type, NULL, 1);
+ if (!fd) // try shared base ctor instead
+ fd = resolveFuncCall(cldec->loc, sc2, cldec->baseClass->ctor, NULL, cldec->type->sharedOf(), NULL, 1);
+ if (fd && !fd->errors)
+ {
+ //printf("Creating default this(){} for class %s\n", cldec->toChars());
+ TypeFunction *btf = fd->type->toTypeFunction();
+ TypeFunction *tf = new TypeFunction(ParameterList(), NULL, LINKd, fd->storage_class);
+ tf->mod = btf->mod;
+ tf->purity = btf->purity;
+ tf->isnothrow = btf->isnothrow;
+ tf->isnogc = btf->isnogc;
+ tf->trust = btf->trust;
+
+ CtorDeclaration *ctor = new CtorDeclaration(cldec->loc, Loc(), 0, tf);
+ ctor->fbody = new CompoundStatement(Loc(), new Statements());
+
+ cldec->members->push(ctor);
+ ctor->addMember(sc, cldec);
+ dsymbolSemantic(ctor, sc2);
+
+ cldec->ctor = ctor;
+ cldec->defaultCtor = ctor;
+ }
+ else
+ {
+ cldec->error("cannot implicitly generate a default ctor when base class %s is missing a default ctor",
+ cldec->baseClass->toPrettyChars());
+ }
+ }
+
+ cldec->dtor = buildDtor(cldec, sc2);
+
+ if (FuncDeclaration *f = hasIdentityOpAssign(cldec, sc2))
+ {
+ if (!(f->storage_class & STCdisable))
+ cldec->error(f->loc, "identity assignment operator overload is illegal");
+ }
+
+ cldec->inv = buildInv(cldec, sc2);
+
+ Module::dprogress++;
+ cldec->semanticRun = PASSsemanticdone;
+ //printf("-ClassDeclaration.semantic(%s), type = %p\n", cldec->toChars(), cldec->type);
+ //members.print();
+
+ sc2->pop();
+
+ if (cldec->type->ty == Tclass && ((TypeClass *)cldec->type)->sym != cldec)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=17492
+ ClassDeclaration *cd = ((TypeClass *)cldec->type)->sym;
+ cldec->error("already exists at %s. Perhaps in another function with the same name?", cd->loc.toChars());
+ }
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ cldec->type = Type::terror;
+ cldec->errors = true;
+ if (cldec->deferred)
+ cldec->deferred->errors = true;
+ }
+
+ // Verify fields of a synchronized class are not public
+ if (cldec->storage_class & STCsynchronized)
+ {
+ for (size_t i = 0; i < cldec->fields.length; i++)
+ {
+ VarDeclaration *vd = cldec->fields[i];
+ if (!vd->isThisDeclaration() &&
+ !vd->prot().isMoreRestrictiveThan(Prot(Prot::public_)))
+ {
+ vd->error("Field members of a synchronized class cannot be %s",
+ protectionToChars(vd->prot().kind));
+ }
+ }
+ }
+
+ if (cldec->deferred && !global.gag)
+ {
+ semantic2(cldec->deferred, sc);
+ semantic3(cldec->deferred, sc);
+ }
+ //printf("-ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec);
+ }
+
+ void visit(InterfaceDeclaration *idec)
+ {
+ //printf("InterfaceDeclaration::semantic(%s), type = %p\n", idec->toChars(), idec->type);
+ if (idec->semanticRun >= PASSsemanticdone)
+ return;
+ unsigned errors = global.errors;
+
+ //printf("+InterfaceDeclaration.semantic(%s), type = %p\n", idec->toChars(), idec->type);
+
+ Scope *scx = NULL;
+ if (idec->_scope)
+ {
+ sc = idec->_scope;
+ scx = idec->_scope; // save so we don't make redundant copies
+ idec->_scope = NULL;
+ }
+
+ if (!idec->parent)
+ {
+ assert(sc->parent && sc->func);
+ idec->parent = sc->parent;
+ }
+ assert(idec->parent && !idec->isAnonymous());
+
+ if (idec->errors)
+ idec->type = Type::terror;
+ idec->type = typeSemantic(idec->type, idec->loc, sc);
+
+ if (idec->type->ty == Tclass && ((TypeClass *)idec->type)->sym != idec)
+ {
+ TemplateInstance *ti = ((TypeClass *)idec->type)->sym->isInstantiated();
+ if (ti && isError(ti))
+ ((TypeClass *)idec->type)->sym = idec;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = idec->ungagSpeculative();
+
+ if (idec->semanticRun == PASSinit)
+ {
+ idec->protection = sc->protection;
+
+ idec->storage_class |= sc->stc;
+ if (idec->storage_class & STCdeprecated)
+ idec->isdeprecated = true;
+
+ idec->userAttribDecl = sc->userAttribDecl;
+ }
+ else if (idec->symtab)
+ {
+ if (idec->sizeok == SIZEOKdone || !scx)
+ {
+ idec->semanticRun = PASSsemanticdone;
+ return;
+ }
+ }
+ idec->semanticRun = PASSsemantic;
+
+ if (idec->baseok < BASEOKdone)
+ {
+ idec->baseok = BASEOKin;
+
+ // Expand any tuples in baseclasses[]
+ for (size_t i = 0; i < idec->baseclasses->length; )
+ {
+ BaseClass *b = (*idec->baseclasses)[i];
+ b->type = resolveBase(idec, sc, scx, b->type);
+
+ Type *tb = b->type->toBasetype();
+ if (tb->ty == Ttuple)
+ {
+ TypeTuple *tup = (TypeTuple *)tb;
+ idec->baseclasses->remove(i);
+ size_t dim = Parameter::dim(tup->arguments);
+ for (size_t j = 0; j < dim; j++)
+ {
+ Parameter *arg = Parameter::getNth(tup->arguments, j);
+ b = new BaseClass(arg->type);
+ idec->baseclasses->insert(i + j, b);
+ }
+ }
+ else
+ i++;
+ }
+
+ if (idec->baseok >= BASEOKdone)
+ {
+ //printf("%s already semantic analyzed, semanticRun = %d\n", idec->toChars(), idec->semanticRun);
+ if (idec->semanticRun >= PASSsemanticdone)
+ return;
+ goto Lancestorsdone;
+ }
+
+ if (!idec->baseclasses->length && sc->linkage == LINKcpp)
+ idec->classKind = ClassKind::cpp;
+ if (sc->linkage == LINKobjc)
+ objc()->setObjc(idec);
+
+ // Check for errors, handle forward references
+ for (size_t i = 0; i < idec->baseclasses->length; )
+ {
+ BaseClass *b = (*idec->baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+ if (!tc || !tc->sym->isInterfaceDeclaration())
+ {
+ if (b->type != Type::terror)
+ idec->error("base type must be interface, not %s", b->type->toChars());
+ idec->baseclasses->remove(i);
+ continue;
+ }
+
+ // Check for duplicate interfaces
+ for (size_t j = 0; j < i; j++)
+ {
+ BaseClass *b2 = (*idec->baseclasses)[j];
+ if (b2->sym == tc->sym)
+ {
+ idec->error("inherits from duplicate interface %s", b2->sym->toChars());
+ idec->baseclasses->remove(i);
+ continue;
+ }
+ }
+
+ if (tc->sym == idec || idec->isBaseOf2(tc->sym))
+ {
+ idec->error("circular inheritance of interface");
+ idec->baseclasses->remove(i);
+ continue;
+ }
+
+ if (tc->sym->isDeprecated())
+ {
+ if (!idec->isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ idec->isdeprecated = true;
+
+ tc->checkDeprecated(idec->loc, sc);
+ }
+ }
+
+ b->sym = tc->sym;
+
+ if (tc->sym->baseok < BASEOKdone)
+ resolveBase(idec, sc, scx, tc->sym); // Try to resolve forward reference
+ if (tc->sym->baseok < BASEOKdone)
+ {
+ //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ idec->baseok = BASEOKnone;
+ }
+ i++;
+ }
+ if (idec->baseok == BASEOKnone)
+ {
+ // Forward referencee of one or more bases, try again later
+ idec->_scope = scx ? scx : sc->copy();
+ idec->_scope->setNoFree();
+ idec->_scope->_module->addDeferredSemantic(idec);
+ return;
+ }
+ idec->baseok = BASEOKdone;
+
+ idec->interfaces.length = idec->baseclasses->length;
+ idec->interfaces.ptr = idec->baseclasses->tdata();
+
+ for (size_t i = 0; i < idec->interfaces.length; i++)
+ {
+ BaseClass *b = idec->interfaces.ptr[i];
+ // If this is an interface, and it derives from a COM interface,
+ // then this is a COM interface too.
+ if (b->sym->isCOMinterface())
+ idec->com = true;
+ if (b->sym->isCPPinterface())
+ idec->classKind = ClassKind::cpp;
+ }
+
+ interfaceSemantic(idec);
+ }
+ Lancestorsdone:
+
+ if (!idec->members) // if opaque declaration
+ {
+ idec->semanticRun = PASSsemanticdone;
+ return;
+ }
+ if (!idec->symtab)
+ idec->symtab = new DsymbolTable();
+
+ for (size_t i = 0; i < idec->baseclasses->length; i++)
+ {
+ BaseClass *b = (*idec->baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ assert(tb->ty == Tclass);
+ TypeClass *tc = (TypeClass *)tb;
+
+ if (tc->sym->semanticRun < PASSsemanticdone)
+ {
+ // Forward referencee of one or more bases, try again later
+ idec->_scope = scx ? scx : sc->copy();
+ idec->_scope->setNoFree();
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ idec->_scope->_module->addDeferredSemantic(idec);
+ return;
+ }
+ }
+
+ if (idec->baseok == BASEOKdone)
+ {
+ idec->baseok = BASEOKsemanticdone;
+
+ // initialize vtbl
+ if (idec->vtblOffset())
+ idec->vtbl.push(idec); // leave room at vtbl[0] for classinfo
+
+ // Cat together the vtbl[]'s from base cldec->interfaces
+ for (size_t i = 0; i < idec->interfaces.length; i++)
+ {
+ BaseClass *b = idec->interfaces.ptr[i];
+
+ // Skip if b has already appeared
+ for (size_t k = 0; k < i; k++)
+ {
+ if (b == idec->interfaces.ptr[k])
+ goto Lcontinue;
+ }
+
+ // Copy vtbl[] from base class
+ if (b->sym->vtblOffset())
+ {
+ size_t d = b->sym->vtbl.length;
+ if (d > 1)
+ {
+ idec->vtbl.reserve(d - 1);
+ for (size_t j = 1; j < d; j++)
+ idec->vtbl.push(b->sym->vtbl[j]);
+ }
+ }
+ else
+ {
+ idec->vtbl.append(&b->sym->vtbl);
+ }
+
+ Lcontinue:
+ ;
+ }
+ }
+
+ for (size_t i = 0; i < idec->members->length; i++)
+ {
+ Dsymbol *s = (*idec->members)[i];
+ s->addMember(sc, idec);
+ }
+
+ Scope *sc2 = idec->newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ for (size_t i = 0; i < idec->members->length; i++)
+ {
+ Dsymbol *s = (*idec->members)[i];
+ //printf("setScope %s %s\n", s->kind(), s->toChars());
+ s->setScope(sc2);
+ }
+
+ for (size_t i = 0; i < idec->members->length; i++)
+ {
+ Dsymbol *s = (*idec->members)[i];
+ s->importAll(sc2);
+ }
+
+ for (size_t i = 0; i < idec->members->length; i++)
+ {
+ Dsymbol *s = (*idec->members)[i];
+ dsymbolSemantic(s, sc2);
+ }
+
+ Module::dprogress++;
+ idec->semanticRun = PASSsemanticdone;
+ //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", idec->toChars(), idec->type);
+ //members->print();
+
+ sc2->pop();
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ idec->type = Type::terror;
+ }
+
+ assert(idec->type->ty != Tclass || ((TypeClass *)idec->type)->sym == idec);
+ }
+};
+
+void templateInstanceSemantic(TemplateInstance *tempinst, Scope *sc, Expressions *fargs)
+{
+ //printf("[%s] TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst->loc.toChars(), tempinst->toChars(), tempinst, global.gag, sc);
+ if (tempinst->inst) // if semantic() was already run
+ {
+ return;
+ }
+ if (tempinst->semanticRun != PASSinit)
+ {
+ Ungag ungag(global.gag);
+ if (!tempinst->gagged)
+ global.gag = 0;
+ tempinst->error(tempinst->loc, "recursive template expansion");
+ if (tempinst->gagged)
+ tempinst->semanticRun = PASSinit;
+ else
+ tempinst->inst = tempinst;
+ tempinst->errors = true;
+ return;
+ }
+
+ // Get the enclosing template instance from the scope tinst
+ tempinst->tinst = sc->tinst;
+
+ // Get the instantiating module from the scope minst
+ tempinst->minst = sc->minst;
+ // Bugzilla 10920: If the enclosing function is non-root symbol,
+ // this instance should be speculative.
+ if (!tempinst->tinst && sc->func && sc->func->inNonRoot())
+ {
+ tempinst->minst = NULL;
+ }
+
+ tempinst->gagged = (global.gag > 0);
+
+ tempinst->semanticRun = PASSsemantic;
+
+ /* Find template declaration first,
+ * then run semantic on each argument (place results in tiargs[]),
+ * last find most specialized template from overload list/set.
+ */
+ if (!tempinst->findTempDecl(sc, NULL) ||
+ !tempinst->semanticTiargs(sc) ||
+ !tempinst->findBestMatch(sc, fargs))
+ {
+Lerror:
+ if (tempinst->gagged)
+ {
+ // Bugzilla 13220: Rollback status for later semantic re-running.
+ tempinst->semanticRun = PASSinit;
+ }
+ else
+ tempinst->inst = tempinst;
+ tempinst->errors = true;
+ return;
+ }
+ TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ // If tempdecl is a mixin, disallow it
+ if (tempdecl->ismixin)
+ {
+ tempinst->error("mixin templates are not regular templates");
+ goto Lerror;
+ }
+
+ tempinst->hasNestedArgs(tempinst->tiargs, tempdecl->isstatic);
+ if (tempinst->errors)
+ goto Lerror;
+
+ /* See if there is an existing TemplateInstantiation that already
+ * implements the typeargs. If so, just refer to that one instead.
+ */
+ tempinst->inst = tempdecl->findExistingInstance(tempinst, fargs);
+ TemplateInstance *errinst = NULL;
+ if (!tempinst->inst)
+ {
+ // So, we need to implement 'this' instance.
+ }
+ else if (tempinst->inst->gagged && !tempinst->gagged && tempinst->inst->errors)
+ {
+ // If the first instantiation had failed, re-run semantic,
+ // so that error messages are shown.
+ errinst = tempinst->inst;
+ }
+ else
+ {
+ // It's a match
+ tempinst->parent = tempinst->inst->parent;
+ tempinst->errors = tempinst->inst->errors;
+
+ // If both this and the previous instantiation were gagged,
+ // use the number of errors that happened last time.
+ global.errors += tempinst->errors;
+ global.gaggedErrors += tempinst->errors;
+
+ // If the first instantiation was gagged, but this is not:
+ if (tempinst->inst->gagged)
+ {
+ // It had succeeded, mark it is a non-gagged instantiation,
+ // and reuse it.
+ tempinst->inst->gagged = tempinst->gagged;
+ }
+
+ tempinst->tnext = tempinst->inst->tnext;
+ tempinst->inst->tnext = tempinst;
+
+ /* A module can have explicit template instance and its alias
+ * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`).
+ * If the first instantiation 'inst' had happened in non-root module,
+ * compiler can assume that its instantiated code would be included
+ * in the separately compiled obj/lib file (e.g. phobos.lib).
+ *
+ * However, if 'this' second instantiation happened in root module,
+ * compiler might need to invoke its codegen (Bugzilla 2500 & 2644).
+ * But whole import graph is not determined until all semantic pass finished,
+ * so 'inst' should conservatively finish the semantic3 pass for the codegen.
+ */
+ if (tempinst->minst && tempinst->minst->isRoot() && !(tempinst->inst->minst && tempinst->inst->minst->isRoot()))
+ {
+ /* Swap the position of 'inst' and 'this' in the instantiation graph.
+ * Then, the primary instance `inst` will be changed to a root instance,
+ * along with all members of `inst` having their scopes updated.
+ *
+ * Before:
+ * non-root -> A!() -> B!()[inst] -> C!() { members[non-root] }
+ * |
+ * root -> D!() -> B!()[this]
+ *
+ * After:
+ * non-root -> A!() -> B!()[this]
+ * |
+ * root -> D!() -> B!()[inst] -> C!() { members[root] }
+ */
+ Module *mi = tempinst->minst;
+ TemplateInstance *ti = tempinst->tinst;
+ tempinst->minst = tempinst->inst->minst;
+ tempinst->tinst = tempinst->inst->tinst;
+ tempinst->inst->minst = mi;
+ tempinst->inst->tinst = ti;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=21299
+ `minst` has been updated on the primary instance `inst` so it is
+ now coming from a root module, however all Dsymbol `inst.members`
+ of the instance still have their `_scope.minst` pointing at the
+ original non-root module. We must now propagate `minst` to all
+ members so that forward referenced dependencies that get
+ instantiated will also be appended to the root module, otherwise
+ there will be undefined references at link-time. */
+ class InstMemberWalker : public Visitor
+ {
+ public:
+ TemplateInstance *inst;
+
+ InstMemberWalker(TemplateInstance *inst)
+ : inst(inst) { }
+
+ void visit(Dsymbol *d)
+ {
+ if (d->_scope)
+ d->_scope->minst = inst->minst;
+ }
+
+ void visit(ScopeDsymbol *sds)
+ {
+ if (!sds->members)
+ return;
+ for (size_t i = 0; i < sds->members->length; i++)
+ {
+ Dsymbol *s = (*sds->members)[i];
+ s->accept(this);
+ }
+ visit((Dsymbol *)sds);
+ }
+
+ void visit(AttribDeclaration *ad)
+ {
+ Dsymbols *d = ad->include(NULL);
+ if (!d)
+ return;
+ for (size_t i = 0; i < d->length; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->accept(this);
+ }
+ visit((Dsymbol *)ad);
+ }
+
+ void visit(ConditionalDeclaration *cd)
+ {
+ if (cd->condition->inc)
+ visit((AttribDeclaration *)cd);
+ else
+ visit((Dsymbol *)cd);
+ }
+ };
+ InstMemberWalker v(tempinst->inst);
+ tempinst->inst->accept(&v);
+
+ if (tempinst->minst) // if inst was not speculative
+ {
+ /* Add 'inst' once again to the root module members[], then the
+ * instance members will get codegen chances.
+ */
+ tempinst->inst->appendToModuleMember();
+ }
+ }
+
+ return;
+ }
+ unsigned errorsave = global.errors;
+
+ tempinst->inst = tempinst;
+ tempinst->parent = tempinst->enclosing ? tempinst->enclosing : tempdecl->parent;
+ //printf("parent = '%s'\n", tempinst->parent->kind());
+
+ TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(tempinst);
+
+ //getIdent();
+
+ // Store the place we added it to in target_symbol_list(_idx) so we can
+ // remove it later if we encounter an error.
+ Dsymbols *target_symbol_list = tempinst->appendToModuleMember();
+ size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list->length - 1 : 0;
+
+ // Copy the syntax trees from the TemplateDeclaration
+ tempinst->members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+
+ // resolve TemplateThisParameter
+ for (size_t i = 0; i < tempdecl->parameters->length; i++)
+ {
+ if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL)
+ continue;
+ Type *t = isType((*tempinst->tiargs)[i]);
+ assert(t);
+ if (StorageClass stc = ModToStc(t->mod))
+ {
+ //printf("t = %s, stc = x%llx\n", t->toChars(), stc);
+ Dsymbols *s = new Dsymbols();
+ s->push(new StorageClassDeclaration(stc, tempinst->members));
+ tempinst->members = s;
+ }
+ break;
+ }
+
+ // Create our own scope for the template parameters
+ Scope *scope = tempdecl->_scope;
+ if (tempdecl->semanticRun == PASSinit)
+ {
+ tempinst->error("template instantiation %s forward references template declaration %s", tempinst->toChars(), tempdecl->toChars());
+ return;
+ }
+
+ tempinst->argsym = new ScopeDsymbol();
+ tempinst->argsym->parent = scope->parent;
+ scope = scope->push(tempinst->argsym);
+ scope->tinst = tempinst;
+ scope->minst = tempinst->minst;
+ //scope->stc = 0;
+
+ // Declare each template parameter as an alias for the argument type
+ Scope *paramscope = scope->push();
+ paramscope->stc = 0;
+ paramscope->protection = Prot(Prot::public_); // Bugzilla 14169: template parameters should be public
+ tempinst->declareParameters(paramscope);
+ paramscope->pop();
+
+ // Add members of template instance to template instance symbol table
+// tempinst->parent = scope->scopesym;
+ tempinst->symtab = new DsymbolTable();
+ for (size_t i = 0; i < tempinst->members->length; i++)
+ {
+ Dsymbol *s = (*tempinst->members)[i];
+ s->addMember(scope, tempinst);
+ }
+
+ /* See if there is only one member of template instance, and that
+ * member has the same name as the template instance.
+ * If so, this template instance becomes an alias for that member.
+ */
+ //printf("members->length = %d\n", tempinst->members->length);
+ if (tempinst->members->length)
+ {
+ Dsymbol *s;
+ if (Dsymbol::oneMembers(tempinst->members, &s, tempdecl->ident) && s)
+ {
+ //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
+ //printf("setting aliasdecl\n");
+ tempinst->aliasdecl = s;
+ }
+ }
+
+ /* If function template declaration
+ */
+ if (fargs && tempinst->aliasdecl)
+ {
+ FuncDeclaration *fd = tempinst->aliasdecl->isFuncDeclaration();
+ if (fd)
+ {
+ /* Transmit fargs to type so that TypeFunction::semantic() can
+ * resolve any "auto ref" storage classes.
+ */
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (tf && tf->ty == Tfunction)
+ tf->fargs = fargs;
+ }
+ }
+
+ // Do semantic() analysis on template instance members
+ Scope *sc2;
+ sc2 = scope->push(tempinst);
+ //printf("enclosing = %d, sc->parent = %s\n", tempinst->enclosing, sc->parent->toChars());
+ sc2->parent = tempinst;
+ sc2->tinst = tempinst;
+ sc2->minst = tempinst->minst;
+
+ tempinst->tryExpandMembers(sc2);
+
+ tempinst->semanticRun = PASSsemanticdone;
+
+ /* ConditionalDeclaration may introduce eponymous declaration,
+ * so we should find it once again after semantic.
+ */
+ if (tempinst->members->length)
+ {
+ Dsymbol *s;
+ if (Dsymbol::oneMembers(tempinst->members, &s, tempdecl->ident) && s)
+ {
+ if (!tempinst->aliasdecl || tempinst->aliasdecl != s)
+ {
+ //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
+ //printf("setting aliasdecl 2\n");
+ tempinst->aliasdecl = s;
+ }
+ }
+ }
+
+ if (global.errors != errorsave)
+ goto Laftersemantic;
+
+ /* If any of the instantiation members didn't get semantic() run
+ * on them due to forward references, we cannot run semantic2()
+ * or semantic3() yet.
+ */
+ {
+ bool found_deferred_ad = false;
+ for (size_t i = 0; i < Module::deferred.length; i++)
+ {
+ Dsymbol *sd = Module::deferred[i];
+ AggregateDeclaration *ad = sd->isAggregateDeclaration();
+ if (ad && ad->parent && ad->parent->isTemplateInstance())
+ {
+ //printf("deferred template aggregate: %s %s\n",
+ // sd->parent->toChars(), sd->toChars());
+ found_deferred_ad = true;
+ if (ad->parent == tempinst)
+ {
+ ad->deferred = tempinst;
+ break;
+ }
+ }
+ }
+ if (found_deferred_ad || Module::deferred.length)
+ goto Laftersemantic;
+ }
+
+ /* The problem is when to parse the initializer for a variable.
+ * Perhaps VarDeclaration::semantic() should do it like it does
+ * for initializers inside a function.
+ */
+ //if (sc->parent->isFuncDeclaration())
+ {
+ /* BUG 782: this has problems if the classes this depends on
+ * are forward referenced. Find a way to defer semantic()
+ * on this template.
+ */
+ semantic2(tempinst, sc2);
+ }
+ if (global.errors != errorsave)
+ goto Laftersemantic;
+
+ if ((sc->func || (sc->flags & SCOPEfullinst)) && !tempinst->tinst)
+ {
+ /* If a template is instantiated inside function, the whole instantiation
+ * should be done at that position. But, immediate running semantic3 of
+ * dependent templates may cause unresolved forward reference (Bugzilla 9050).
+ * To avoid the issue, don't run semantic3 until semantic and semantic2 done.
+ */
+ TemplateInstances deferred;
+ tempinst->deferred = &deferred;
+
+ //printf("Run semantic3 on %s\n", tempinst->toChars());
+ tempinst->trySemantic3(sc2);
+
+ for (size_t i = 0; i < deferred.length; i++)
+ {
+ //printf("+ run deferred semantic3 on %s\n", deferred[i]->toChars());
+ semantic3(deferred[i], NULL);
+ }
+
+ tempinst->deferred = NULL;
+ }
+ else if (tempinst->tinst)
+ {
+ bool doSemantic3 = false;
+ if (sc->func && tempinst->aliasdecl && tempinst->aliasdecl->toAlias()->isFuncDeclaration())
+ {
+ /* Template function instantiation should run semantic3 immediately
+ * for attribute inference.
+ */
+ tempinst->trySemantic3(sc2);
+ }
+ else if (sc->func)
+ {
+ /* A lambda function in template arguments might capture the
+ * instantiated scope context. For the correct context inference,
+ * all instantiated functions should run the semantic3 immediately.
+ * See also compilable/test14973.d
+ */
+ for (size_t i = 0; i < tempinst->tdtypes.length; i++)
+ {
+ RootObject *oarg = tempinst->tdtypes[i];
+ Dsymbol *s = getDsymbol(oarg);
+ if (!s)
+ continue;
+
+ if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ {
+ if (!td->literal)
+ continue;
+ assert(td->members && td->members->length == 1);
+ s = (*td->members)[0];
+ }
+ if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
+ {
+ if (fld->tok == TOKreserved)
+ {
+ doSemantic3 = true;
+ break;
+ }
+ }
+ }
+ //printf("[%s] %s doSemantic3 = %d\n", tempinst->loc.toChars(), tempinst->toChars(), doSemantic3);
+ }
+ if (doSemantic3)
+ tempinst->trySemantic3(sc2);
+
+ TemplateInstance *ti = tempinst->tinst;
+ int nest = 0;
+ while (ti && !ti->deferred && ti->tinst)
+ {
+ ti = ti->tinst;
+ if (++nest > global.recursionLimit)
+ {
+ global.gag = 0; // ensure error message gets printed
+ tempinst->error("recursive expansion");
+ fatal();
+ }
+ }
+ if (ti && ti->deferred)
+ {
+ //printf("deferred semantic3 of %p %s, ti = %s, ti->deferred = %p\n", tempinst, tempinst->toChars(), ti->toChars());
+ for (size_t i = 0; ; i++)
+ {
+ if (i == ti->deferred->length)
+ {
+ ti->deferred->push(tempinst);
+ break;
+ }
+ if ((*ti->deferred)[i] == tempinst)
+ break;
+ }
+ }
+ }
+
+ if (tempinst->aliasdecl)
+ {
+ /* Bugzilla 13816: AliasDeclaration tries to resolve forward reference
+ * twice (See inuse check in AliasDeclaration::toAlias()). It's
+ * necessary to resolve mutual references of instantiated symbols, but
+ * it will left a true recursive alias in tuple declaration - an
+ * AliasDeclaration A refers TupleDeclaration B, and B contains A
+ * in its elements. To correctly make it an error, we strictly need to
+ * resolve the alias of eponymous member.
+ */
+ tempinst->aliasdecl = tempinst->aliasdecl->toAlias2();
+ }
+
+ Laftersemantic:
+ sc2->pop();
+
+ scope->pop();
+
+ // Give additional context info if error occurred during instantiation
+ if (global.errors != errorsave)
+ {
+ if (!tempinst->errors)
+ {
+ if (!tempdecl->literal)
+ tempinst->error(tempinst->loc, "error instantiating");
+ if (tempinst->tinst)
+ tempinst->tinst->printInstantiationTrace();
+ }
+ tempinst->errors = true;
+ if (tempinst->gagged)
+ {
+ // Errors are gagged, so remove the template instance from the
+ // instance/symbol lists we added it to and reset our state to
+ // finish clean and so we can try to instantiate it again later
+ // (see bugzilla 4302 and 6602).
+ tempdecl->removeInstance(tempdecl_instance_idx);
+ if (target_symbol_list)
+ {
+ // Because we added 'this' in the last position above, we
+ // should be able to remove it without messing other indices up.
+ assert((*target_symbol_list)[target_symbol_list_idx] == tempinst);
+ target_symbol_list->remove(target_symbol_list_idx);
+ tempinst->memberOf = NULL; // no longer a member
+ }
+ tempinst->semanticRun = PASSinit;
+ tempinst->inst = NULL;
+ tempinst->symtab = NULL;
+ }
+ }
+ else if (errinst)
+ {
+ /* Bugzilla 14541: If the previous gagged instance had failed by
+ * circular references, currrent "error reproduction instantiation"
+ * might succeed, because of the difference of instantiated context.
+ * On such case, the cached error instance needs to be overridden by the
+ * succeeded instance.
+ */
+ //printf("replaceInstance()\n");
+ TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)tempdecl->instances, (void *)tempinst->hash);
+ assert(tinstances);
+ for (size_t i = 0; i < tinstances->length; i++)
+ {
+ TemplateInstance *ti = (*tinstances)[i];
+ if (ti == errinst)
+ {
+ (*tinstances)[i] = tempinst; // override
+ break;
+ }
+ }
+ }
+}
+
+// function used to perform semantic on AliasDeclaration
+void aliasSemantic(AliasDeclaration *ds, Scope *sc)
+{
+ //printf("AliasDeclaration::semantic() %s\n", ds->toChars());
+
+ // as AliasDeclaration::semantic, in case we're called first.
+ // see https://issues.dlang.org/show_bug.cgi?id=21001
+ ds->storage_class |= sc->stc & STCdeprecated;
+ ds->protection = sc->protection;
+ ds->userAttribDecl = sc->userAttribDecl;
+
+ // TypeTraits needs to know if it's located in an AliasDeclaration
+ sc->flags |= SCOPEalias;
+
+ if (ds->aliassym)
+ {
+ FuncDeclaration *fd = ds->aliassym->isFuncLiteralDeclaration();
+ TemplateDeclaration *td = ds->aliassym->isTemplateDeclaration();
+ if (fd || (td && td->literal))
+ {
+ if (fd && fd->semanticRun >= PASSsemanticdone)
+ {
+ sc->flags &= ~SCOPEalias;
+ return;
+ }
+
+ Expression *e = new FuncExp(ds->loc, ds->aliassym);
+ e = expressionSemantic(e, sc);
+ if (e->op == TOKfunction)
+ {
+ FuncExp *fe = (FuncExp *)e;
+ ds->aliassym = fe->td ? (Dsymbol *)fe->td : fe->fd;
+ }
+ else
+ {
+ ds->aliassym = NULL;
+ ds->type = Type::terror;
+ }
+ sc->flags &= ~SCOPEalias;
+ return;
+ }
+
+ if (ds->aliassym->isTemplateInstance())
+ dsymbolSemantic(ds->aliassym, sc);
+ sc->flags &= ~SCOPEalias;
+ return;
+ }
+ ds->inuse = 1;
+
+ // Given:
+ // alias foo.bar.abc def;
+ // it is not knowable from the syntax whether this is an alias
+ // for a type or an alias for a symbol. It is up to the semantic()
+ // pass to distinguish.
+ // If it is a type, then type is set and getType() will return that
+ // type. If it is a symbol, then aliassym is set and type is NULL -
+ // toAlias() will return aliasssym.
+
+ unsigned int errors = global.errors;
+ Type *oldtype = ds->type;
+
+ // Ungag errors when not instantiated DeclDefs scope alias
+ Ungag ungag(global.gag);
+ //printf("%s parent = %s, gag = %d, instantiated = %d\n", ds->toChars(), ds->parent, global.gag, ds->isInstantiated());
+ if (ds->parent && global.gag && !ds->isInstantiated() && !ds->toParent2()->isFuncDeclaration())
+ {
+ //printf("%s type = %s\n", ds->toPrettyChars(), ds->type->toChars());
+ global.gag = 0;
+ }
+
+ /* This section is needed because Type::resolve() will:
+ * const x = 3;
+ * alias y = x;
+ * try to convert identifier x to 3.
+ */
+ Dsymbol *s = ds->type->toDsymbol(sc);
+ if (errors != global.errors)
+ {
+ s = NULL;
+ ds->type = Type::terror;
+ }
+ if (s && s == ds)
+ {
+ ds->error("cannot resolve");
+ s = NULL;
+ ds->type = Type::terror;
+ }
+ if (!s || !s->isEnumMember())
+ {
+ Type *t;
+ Expression *e;
+ Scope *sc2 = sc;
+ if (ds->storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCdisable))
+ {
+ // For 'ref' to be attached to function types, and picked
+ // up by Type::resolve(), it has to go into sc.
+ sc2 = sc->push();
+ sc2->stc |= ds->storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCshared | STCdisable);
+ }
+ ds->type = ds->type->addSTC(ds->storage_class);
+ ds->type->resolve(ds->loc, sc2, &e, &t, &s);
+ if (sc2 != sc)
+ sc2->pop();
+
+ if (e) // Try to convert Expression to Dsymbol
+ {
+ s = getDsymbol(e);
+ if (!s)
+ {
+ if (e->op != TOKerror)
+ ds->error("cannot alias an expression %s", e->toChars());
+ t = Type::terror;
+ }
+ }
+ ds->type = t;
+ }
+ if (s == ds)
+ {
+ assert(global.errors);
+ ds->type = Type::terror;
+ s = NULL;
+ }
+ if (!s) // it's a type alias
+ {
+ //printf("alias %s resolved to type %s\n", ds->toChars(), ds->type->toChars());
+ ds->type = typeSemantic(ds->type, ds->loc, sc);
+ ds->aliassym = NULL;
+ }
+ else // it's a symbolic alias
+ {
+ //printf("alias %s resolved to %s %s\n", ds->toChars(), s->kind(), s->toChars());
+ ds->type = NULL;
+ ds->aliassym = s;
+ }
+ if (global.gag && errors != global.errors)
+ {
+ ds->type = oldtype;
+ ds->aliassym = NULL;
+ }
+ ds->inuse = 0;
+ ds->semanticRun = PASSsemanticdone;
+
+ if (Dsymbol *sx = ds->overnext)
+ {
+ ds->overnext = NULL;
+
+ if (!ds->overloadInsert(sx))
+ ScopeDsymbol::multiplyDefined(Loc(), sx, ds);
+ }
+ sc->flags &= ~SCOPEalias;
+}
+
+
+/*************************************
+ * Does semantic analysis on the public face of declarations.
+ */
+void dsymbolSemantic(Dsymbol *dsym, Scope *sc)
+{
+ DsymbolSemanticVisitor v(sc);
+ dsym->accept(&v);
+}
/* 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.
static int arrayObjectMatch(Objects *oa1, Objects *oa2);
static unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam);
static MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam);
-static bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
-Expression *semantic(Expression *e, Scope *sc);
+bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
/********************************************
Dsymbol::arraySyntaxCopy(members), ismixin, literal);
}
-void TemplateDeclaration::semantic(Scope *sc)
-{
- if (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 (ident == Id::RTInfo)
- Type::rtinfo = this;
- }
-
- /* Remember Scope for later instantiations, but make
- * a copy since attributes can change.
- */
- if (!this->_scope)
- {
- this->_scope = sc->copy();
- this->_scope->setNoFree();
- }
-
- semanticRun = PASSsemantic;
-
- parent = sc->parent;
- protection = sc->protection;
- isstatic = toParent()->isModule() || (_scope->stc & STCstatic);
-
- if (!isstatic)
- {
- if (AggregateDeclaration *ad = parent->pastMixin()->isAggregateDeclaration())
- ad->makeNested();
- }
-
- // Set up scope for parameters
- ScopeDsymbol *paramsym = new ScopeDsymbol();
- paramsym->parent = parent;
- Scope *paramscope = sc->push(paramsym);
- paramscope->stc = 0;
-
- if (global.params.doDocComments)
- {
- origParameters = new TemplateParameters();
- origParameters->setDim(parameters->length);
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *tp = (*parameters)[i];
- (*origParameters)[i] = tp->syntaxCopy();
- }
- }
-
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *tp = (*parameters)[i];
-
- if (!tp->declareParameter(paramscope))
- {
- error(tp->loc, "parameter '%s' multiply defined", tp->ident->toChars());
- errors = true;
- }
- if (!tp->semantic(paramscope, parameters))
- {
- errors = true;
- }
- if (i + 1 != parameters->length && tp->isTemplateTupleParameter())
- {
- error("template tuple parameter must be last one");
- errors = true;
- }
- }
-
- /* Calculate TemplateParameter::dependent
- */
- TemplateParameters tparams;
- tparams.setDim(1);
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *tp = (*parameters)[i];
- tparams[0] = tp;
-
- for (size_t j = 0; j < parameters->length; j++)
- {
- // Skip cases like: X(T : T)
- if (i == j)
- continue;
-
- if (TemplateTypeParameter *ttp = (*parameters)[j]->isTemplateTypeParameter())
- {
- if (reliesOnTident(ttp->specType, &tparams))
- tp->dependent = true;
- }
- else if (TemplateAliasParameter *tap = (*parameters)[j]->isTemplateAliasParameter())
- {
- if (reliesOnTident(tap->specType, &tparams) ||
- reliesOnTident(isType(tap->specAlias), &tparams))
- {
- tp->dependent = true;
- }
- }
- }
- }
-
- paramscope->pop();
-
- // Compute again
- onemember = NULL;
- if (members)
- {
- Dsymbol *s;
- if (Dsymbol::oneMembers(members, &s, ident) && s)
- {
- onemember = s;
- s->parent = this;
- }
- }
-
- /* BUG: should check:
- * o no virtual functions or non-static data members of classes
- */
- semanticRun = PASSsemanticdone;
-}
-
const char *TemplateDeclaration::kind() const
{
return (onemember && onemember->isAggregateDeclaration())
continue; // don't add it, if it has no name
VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL);
v->storage_class = fparam->storageClass;
- v->semantic(scx);
+ dsymbolSemantic(v, scx);
if (!ti->symtab)
ti->symtab = new DsymbolTable();
if (!scx->insert(v))
m = m2;
if (!flag)
- sparam->semantic(paramscope);
+ dsymbolSemantic(sparam, paramscope);
if (!paramscope->insert(sparam)) // TODO: This check can make more early
goto Lnomatch; // in TemplateDeclaration::semantic, and
// then we don't need to make sparam if flags == 0
// Resolve parameter types and 'auto ref's.
tf->fargs = fargs;
unsigned olderrors = global.startGagging();
- fd->type = tf->semantic(loc, paramscope);
+ fd->type = typeSemantic(tf, loc, paramscope);
if (global.endGagging(olderrors))
{
assert(fd->type->ty != Tfunction);
if (m < matchTiargs)
matchTiargs = m;
- sparam->semantic(paramscope);
+ dsymbolSemantic(sparam, paramscope);
if (!paramscope->insert(sparam))
goto Lnomatch;
}
Parameter *p = fparameters[j];
if (!reliesOnTident(p->type, parameters, inferStart))
{
- Type *pt = p->type->syntaxCopy()->semantic(fd->loc, paramscope);
+ Type *pt = typeSemantic(p->type->syntaxCopy(), fd->loc, paramscope);
rem += pt->ty == Ttuple ? ((TypeTuple *)pt)->arguments->length : 1;
}
else
if (!reliesOnTident(prmtype, parameters, inferStart))
{
// should copy prmtype to avoid affecting semantic result
- prmtype = prmtype->syntaxCopy()->semantic(fd->loc, paramscope);
+ prmtype = typeSemantic(prmtype->syntaxCopy(), fd->loc, paramscope);
if (prmtype->ty == Ttuple)
{
// Deduce prmtype from the defaultArg.
farg = fparam->defaultArg->syntaxCopy();
- farg = ::semantic(farg, paramscope);
+ farg = expressionSemantic(farg, paramscope);
farg = resolveProperties(paramscope, farg);
}
else
}
else
{
- Type *vt = tvp->valType->semantic(Loc(), sc);
+ Type *vt = typeSemantic(tvp->valType, Loc(), sc);
MATCH m = (MATCH)dim->implicitConvTo(vt);
if (m <= MATCHnomatch)
goto Lnomatch;
if (!sc->insert(d))
error("declaration %s is already defined", tp->ident->toChars());
- d->semantic(sc);
+ dsymbolSemantic(d, sc);
/* So the caller's o gets updated with the result of semantic() being run on o
*/
fd->semanticRun < PASSsemanticdone)
{
Ungag ungag = fd->ungagSpeculative();
- fd->semantic(NULL);
+ dsymbolSemantic(fd, NULL);
}
if (fd->semanticRun < PASSsemanticdone)
{
{
// Try to fix forward reference. Ungag errors while doing so.
Ungag ungag = td->ungagSpeculative();
- td->semantic(td->_scope);
+ dsymbolSemantic(td, td->_scope);
}
if (td->semanticRun == PASSinit)
{
if (mta <= MATCHnomatch || mta < ta_last) // no match or less match
return 0;
- ti->semantic(sc, fargs);
+ templateInstanceSemantic(ti, sc, fargs);
if (!ti->inst) // if template failed to expand
return 0;
sc = p.td_best->_scope; // workaround for Type::aliasthisOf
TemplateInstance *ti = new TemplateInstance(loc, p.td_best, p.ti_best->tiargs);
- ti->semantic(sc, fargs);
+ templateInstanceSemantic(ti, sc, fargs);
m->lastf = ti->toAlias()->isFuncDeclaration();
if (!m->lastf)
*/
if (tf->next && !m->lastf->inferRetType)
{
- m->lastf->type = tf->semantic(loc, sc);
+ m->lastf->type = typeSemantic(tf, loc, sc);
}
}
else if (m->lastf)
tf->next = NULL;
fd->type = tf;
fd->type = fd->type->addSTC(scx->stc);
- fd->type = fd->type->semantic(fd->loc, scx);
+ fd->type = typeSemantic(fd->type, fd->loc, scx);
scx = scx->pop();
if (fd->type->ty != Tfunction)
/* BUG: what if tparam is a template instance, that
* has as an argument another Tident?
*/
- tparam = tparam->semantic(loc, sc);
+ tparam = typeSemantic(tparam, loc, sc);
assert(tparam->ty != Tident);
result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
return;
loc = tp->loc;
}
- tparam = tparam->semantic(loc, sc);
+ tparam = typeSemantic(tparam, loc, sc);
}
if (t->ty != tparam->ty)
{
// (it may be from a parent template, for example)
}
- e2 = ::semantic(e2, sc); // Bugzilla 13417
+ e2 = expressionSemantic(e2, sc); // Bugzilla 13417
e2 = e2->ctfeInterpret();
//printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty);
Type *t = pto->type->syntaxCopy(); // Bugzilla 11774
if (reliesOnTident(t, parameters, inferStart))
return;
- t = t->semantic(e->loc, sc);
+ t = typeSemantic(t, e->loc, sc);
if (t->ty == Terror)
return;
tiargs->push(t);
TemplateInstance *ti = new TemplateInstance(e->loc, e->td, tiargs);
Expression *ex = new ScopeExp(e->loc, ti);
- ex = ::semantic(ex, e->td->_scope);
+ ex = expressionSemantic(ex, e->td->_scope);
// Reset inference target for the later re-semantic
e->fd->treq = NULL;
return sc->insert(ad) != NULL;
}
-bool TemplateTypeParameter::semantic(Scope *sc, TemplateParameters *parameters)
-{
- //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
- if (specType && !reliesOnTident(specType, parameters))
- {
- specType = specType->semantic(loc, sc);
- }
- return !(specType && isError(specType));
-}
-
MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg,
size_t i, TemplateParameters *parameters, Objects *dedtypes,
Declaration **psparam)
if (t)
{
t = t->syntaxCopy();
- t = t->semantic(loc, sc); // use the parameter loc
+ t = typeSemantic(t, loc, sc); // use the parameter loc
}
return t;
}
return sc->insert(ad) != NULL;
}
-static RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters)
-{
- if (o)
- {
- Expression *ea = isExpression(o);
- Type *ta = isType(o);
- if (ta && (!parameters || !reliesOnTident(ta, parameters)))
- {
- Dsymbol *s = ta->toDsymbol(sc);
- if (s)
- o = s;
- else
- o = ta->semantic(loc, sc);
- }
- else if (ea)
- {
- sc = sc->startCTFE();
- ea = ::semantic(ea, sc);
- sc = sc->endCTFE();
- o = ea->ctfeInterpret();
- }
- }
- return o;
-}
-
-bool TemplateAliasParameter::semantic(Scope *sc, TemplateParameters *parameters)
-{
- if (specType && !reliesOnTident(specType, parameters))
- {
- specType = specType->semantic(loc, sc);
- }
- specAlias = aliasParameterSemantic(loc, sc, specAlias, parameters);
- return !(specType && isError(specType)) &&
- !(specAlias && isError(specAlias));
-}
-
MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg,
size_t i, TemplateParameters *parameters, Objects *dedtypes,
Declaration **psparam)
Initializer *init = new ExpInitializer(loc, ea);
VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
v->storage_class = STCmanifest;
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
*psparam = v;
}
}
return sc->insert(v) != NULL;
}
-bool TemplateValueParameter::semantic(Scope *sc, TemplateParameters *)
-{
- valType = valType->semantic(loc, sc);
-
- return !isError(valType);
-}
-
MATCH TemplateValueParameter::matchArg(Scope *sc, RootObject *oarg,
size_t i, TemplateParameters *, Objects *dedtypes, Declaration **psparam)
{
goto Lnomatch;
ei = new VarExp(loc, f);
- ei = ::semantic(ei, sc);
+ ei = expressionSemantic(ei, sc);
/* If a function is really property-like, and then
* it's CTFEable, ei will be a literal expression.
}
//printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty);
- vt = valType->semantic(loc, sc);
+ vt = typeSemantic(valType, loc, sc);
//printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars());
//printf("vt = %s\n", vt->toChars());
Expression *e = specValue;
sc = sc->startCTFE();
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
e = e->implicitCastTo(sc, vt);
ei = ei->syntaxCopy();
sc = sc->startCTFE();
- ei = ::semantic(ei, sc);
+ ei = expressionSemantic(ei, sc);
sc = sc->endCTFE();
ei = ei->implicitCastTo(sc, vt);
ei = ei->ctfeInterpret();
if (e)
{
e = e->syntaxCopy();
- if ((e = ::semantic(e, sc)) == NULL)
+ if ((e = expressionSemantic(e, sc)) == NULL)
return NULL;
if ((e = resolveProperties(sc, e)) == NULL)
return NULL;
return sc->insert(ad) != NULL;
}
-bool TemplateTupleParameter::semantic(Scope *, TemplateParameters *)
-{
- return true;
-}
-
MATCH TemplateTupleParameter::matchArg(Loc, Scope *sc, Objects *tiargs,
size_t i, TemplateParameters *parameters, Objects *dedtypes,
Declaration **psparam)
return ti;
}
-void TemplateInstance::semantic(Scope *sc)
-{
- semantic(sc, NULL);
-}
-
void TemplateInstance::expandMembers(Scope *sc2)
{
for (size_t i = 0; i < members->length; i++)
// if (enclosing)
// s->parent = sc->parent;
//printf("test3: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
- s->semantic(sc2);
+ dsymbolSemantic(s, sc2);
//printf("test4: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
Module::runDeferredSemantic();
}
error("recursive expansion exceeded allowed nesting limit");
fatal();
}
- semantic3(sc2);
+ semantic3(this, sc2);
--nest;
}
-void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
-{
- //printf("[%s] TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", loc.toChars(), toChars(), this, global.gag, sc);
- if (inst) // if semantic() was already run
- {
- return;
- }
- if (semanticRun != PASSinit)
- {
- Ungag ungag(global.gag);
- if (!gagged)
- global.gag = 0;
- error(loc, "recursive template expansion");
- if (gagged)
- semanticRun = PASSinit;
- else
- inst = this;
- errors = true;
- return;
- }
-
- // Get the enclosing template instance from the scope tinst
- tinst = sc->tinst;
-
- // Get the instantiating module from the scope minst
- minst = sc->minst;
- // Bugzilla 10920: If the enclosing function is non-root symbol,
- // this instance should be speculative.
- if (!tinst && sc->func && sc->func->inNonRoot())
- {
- minst = NULL;
- }
-
- gagged = (global.gag > 0);
-
- semanticRun = PASSsemantic;
-
- /* Find template declaration first,
- * then run semantic on each argument (place results in tiargs[]),
- * last find most specialized template from overload list/set.
- */
- if (!findTempDecl(sc, NULL) ||
- !semanticTiargs(sc) ||
- !findBestMatch(sc, fargs))
- {
-Lerror:
- if (gagged)
- {
- // Bugzilla 13220: Rollback status for later semantic re-running.
- semanticRun = PASSinit;
- }
- else
- inst = this;
- errors = true;
- return;
- }
- TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- // If tempdecl is a mixin, disallow it
- if (tempdecl->ismixin)
- {
- error("mixin templates are not regular templates");
- goto Lerror;
- }
-
- hasNestedArgs(tiargs, tempdecl->isstatic);
- if (errors)
- goto Lerror;
-
- /* See if there is an existing TemplateInstantiation that already
- * implements the typeargs. If so, just refer to that one instead.
- */
- inst = tempdecl->findExistingInstance(this, fargs);
- TemplateInstance *errinst = NULL;
- if (!inst)
- {
- // So, we need to implement 'this' instance.
- }
- else if (inst->gagged && !gagged && inst->errors)
- {
- // If the first instantiation had failed, re-run semantic,
- // so that error messages are shown.
- errinst = inst;
- }
- else
- {
- // It's a match
- parent = inst->parent;
- errors = inst->errors;
-
- // If both this and the previous instantiation were gagged,
- // use the number of errors that happened last time.
- global.errors += errors;
- global.gaggedErrors += errors;
-
- // If the first instantiation was gagged, but this is not:
- if (inst->gagged)
- {
- // It had succeeded, mark it is a non-gagged instantiation,
- // and reuse it.
- inst->gagged = gagged;
- }
-
- this->tnext = inst->tnext;
- inst->tnext = this;
-
- /* A module can have explicit template instance and its alias
- * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`).
- * If the first instantiation 'inst' had happened in non-root module,
- * compiler can assume that its instantiated code would be included
- * in the separately compiled obj/lib file (e.g. phobos.lib).
- *
- * However, if 'this' second instantiation happened in root module,
- * compiler might need to invoke its codegen (Bugzilla 2500 & 2644).
- * But whole import graph is not determined until all semantic pass finished,
- * so 'inst' should conservatively finish the semantic3 pass for the codegen.
- */
- if (minst && minst->isRoot() && !(inst->minst && inst->minst->isRoot()))
- {
- /* Swap the position of 'inst' and 'this' in the instantiation graph.
- * Then, the primary instance `inst` will be changed to a root instance,
- * along with all members of `inst` having their scopes updated.
- *
- * Before:
- * non-root -> A!() -> B!()[inst] -> C!() { members[non-root] }
- * |
- * root -> D!() -> B!()[this]
- *
- * After:
- * non-root -> A!() -> B!()[this]
- * |
- * root -> D!() -> B!()[inst] -> C!() { members[root] }
- */
- Module *mi = minst;
- TemplateInstance *ti = tinst;
- minst = inst->minst;
- tinst = inst->tinst;
- inst->minst = mi;
- inst->tinst = ti;
-
- /* https://issues.dlang.org/show_bug.cgi?id=21299
- `minst` has been updated on the primary instance `inst` so it is
- now coming from a root module, however all Dsymbol `inst.members`
- of the instance still have their `_scope.minst` pointing at the
- original non-root module. We must now propagate `minst` to all
- members so that forward referenced dependencies that get
- instantiated will also be appended to the root module, otherwise
- there will be undefined references at link-time. */
- class InstMemberWalker : public Visitor
- {
- public:
- TemplateInstance *inst;
-
- InstMemberWalker(TemplateInstance *inst)
- : inst(inst) { }
-
- void visit(Dsymbol *d)
- {
- if (d->_scope)
- d->_scope->minst = inst->minst;
- }
-
- void visit(ScopeDsymbol *sds)
- {
- if (!sds->members)
- return;
- for (size_t i = 0; i < sds->members->length; i++)
- {
- Dsymbol *s = (*sds->members)[i];
- s->accept(this);
- }
- visit((Dsymbol *)sds);
- }
-
- void visit(AttribDeclaration *ad)
- {
- Dsymbols *d = ad->include(NULL);
- if (!d)
- return;
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->accept(this);
- }
- visit((Dsymbol *)ad);
- }
-
- void visit(ConditionalDeclaration *cd)
- {
- if (cd->condition->inc)
- visit((AttribDeclaration *)cd);
- else
- visit((Dsymbol *)cd);
- }
- };
- InstMemberWalker v(inst);
- inst->accept(&v);
-
- if (minst) // if inst was not speculative
- {
- /* Add 'inst' once again to the root module members[], then the
- * instance members will get codegen chances.
- */
- inst->appendToModuleMember();
- }
- }
-
- return;
- }
- unsigned errorsave = global.errors;
-
- inst = this;
- parent = enclosing ? enclosing : tempdecl->parent;
- //printf("parent = '%s'\n", parent->kind());
-
- TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this);
-
- //getIdent();
-
- // Store the place we added it to in target_symbol_list(_idx) so we can
- // remove it later if we encounter an error.
- Dsymbols *target_symbol_list = appendToModuleMember();
- size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list->length - 1 : 0;
-
- // Copy the syntax trees from the TemplateDeclaration
- members = Dsymbol::arraySyntaxCopy(tempdecl->members);
-
- // resolve TemplateThisParameter
- for (size_t i = 0; i < tempdecl->parameters->length; i++)
- {
- if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL)
- continue;
- Type *t = isType((*tiargs)[i]);
- assert(t);
- if (StorageClass stc = ModToStc(t->mod))
- {
- //printf("t = %s, stc = x%llx\n", t->toChars(), stc);
- Dsymbols *s = new Dsymbols();
- s->push(new StorageClassDeclaration(stc, members));
- members = s;
- }
- break;
- }
-
- // Create our own scope for the template parameters
- Scope *scope = tempdecl->_scope;
- if (tempdecl->semanticRun == PASSinit)
- {
- error("template instantiation %s forward references template declaration %s", toChars(), tempdecl->toChars());
- return;
- }
-
- argsym = new ScopeDsymbol();
- argsym->parent = scope->parent;
- scope = scope->push(argsym);
- scope->tinst = this;
- scope->minst = minst;
- //scope->stc = 0;
-
- // Declare each template parameter as an alias for the argument type
- Scope *paramscope = scope->push();
- paramscope->stc = 0;
- paramscope->protection = Prot(Prot::public_); // Bugzilla 14169: template parameters should be public
- declareParameters(paramscope);
- paramscope->pop();
-
- // Add members of template instance to template instance symbol table
-// parent = scope->scopesym;
- symtab = new DsymbolTable();
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->addMember(scope, this);
- }
-
- /* See if there is only one member of template instance, and that
- * member has the same name as the template instance.
- * If so, this template instance becomes an alias for that member.
- */
- //printf("members->length = %d\n", members->length);
- if (members->length)
- {
- Dsymbol *s;
- if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s)
- {
- //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
- //printf("setting aliasdecl\n");
- aliasdecl = s;
- }
- }
-
- /* If function template declaration
- */
- if (fargs && aliasdecl)
- {
- FuncDeclaration *fd = aliasdecl->isFuncDeclaration();
- if (fd)
- {
- /* Transmit fargs to type so that TypeFunction::semantic() can
- * resolve any "auto ref" storage classes.
- */
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (tf && tf->ty == Tfunction)
- tf->fargs = fargs;
- }
- }
-
- // Do semantic() analysis on template instance members
- Scope *sc2;
- sc2 = scope->push(this);
- //printf("enclosing = %d, sc->parent = %s\n", enclosing, sc->parent->toChars());
- sc2->parent = this;
- sc2->tinst = this;
- sc2->minst = minst;
-
- tryExpandMembers(sc2);
-
- semanticRun = PASSsemanticdone;
-
- /* ConditionalDeclaration may introduce eponymous declaration,
- * so we should find it once again after semantic.
- */
- if (members->length)
- {
- Dsymbol *s;
- if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s)
- {
- if (!aliasdecl || aliasdecl != s)
- {
- //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
- //printf("setting aliasdecl 2\n");
- aliasdecl = s;
- }
- }
- }
-
- if (global.errors != errorsave)
- goto Laftersemantic;
-
- /* If any of the instantiation members didn't get semantic() run
- * on them due to forward references, we cannot run semantic2()
- * or semantic3() yet.
- */
- {
- bool found_deferred_ad = false;
- for (size_t i = 0; i < Module::deferred.length; i++)
- {
- Dsymbol *sd = Module::deferred[i];
- AggregateDeclaration *ad = sd->isAggregateDeclaration();
- if (ad && ad->parent && ad->parent->isTemplateInstance())
- {
- //printf("deferred template aggregate: %s %s\n",
- // sd->parent->toChars(), sd->toChars());
- found_deferred_ad = true;
- if (ad->parent == this)
- {
- ad->deferred = this;
- break;
- }
- }
- }
- if (found_deferred_ad || Module::deferred.length)
- goto Laftersemantic;
- }
-
- /* The problem is when to parse the initializer for a variable.
- * Perhaps VarDeclaration::semantic() should do it like it does
- * for initializers inside a function.
- */
- //if (sc->parent->isFuncDeclaration())
- {
- /* BUG 782: this has problems if the classes this depends on
- * are forward referenced. Find a way to defer semantic()
- * on this template.
- */
- semantic2(sc2);
- }
- if (global.errors != errorsave)
- goto Laftersemantic;
-
- if ((sc->func || (sc->flags & SCOPEfullinst)) && !tinst)
- {
- /* If a template is instantiated inside function, the whole instantiation
- * should be done at that position. But, immediate running semantic3 of
- * dependent templates may cause unresolved forward reference (Bugzilla 9050).
- * To avoid the issue, don't run semantic3 until semantic and semantic2 done.
- */
- TemplateInstances deferred;
- this->deferred = &deferred;
-
- //printf("Run semantic3 on %s\n", toChars());
- trySemantic3(sc2);
-
- for (size_t i = 0; i < deferred.length; i++)
- {
- //printf("+ run deferred semantic3 on %s\n", deferred[i]->toChars());
- deferred[i]->semantic3(NULL);
- }
-
- this->deferred = NULL;
- }
- else if (tinst)
- {
- bool doSemantic3 = false;
- if (sc->func && aliasdecl && aliasdecl->toAlias()->isFuncDeclaration())
- {
- /* Template function instantiation should run semantic3 immediately
- * for attribute inference.
- */
- trySemantic3(sc2);
- }
- else if (sc->func)
- {
- /* A lambda function in template arguments might capture the
- * instantiated scope context. For the correct context inference,
- * all instantiated functions should run the semantic3 immediately.
- * See also compilable/test14973.d
- */
- for (size_t i = 0; i < tdtypes.length; i++)
- {
- RootObject *oarg = tdtypes[i];
- Dsymbol *s = getDsymbol(oarg);
- if (!s)
- continue;
-
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- if (!td->literal)
- continue;
- assert(td->members && td->members->length == 1);
- s = (*td->members)[0];
- }
- if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
- {
- if (fld->tok == TOKreserved)
- {
- doSemantic3 = true;
- break;
- }
- }
- }
- //printf("[%s] %s doSemantic3 = %d\n", loc.toChars(), toChars(), doSemantic3);
- }
- if (doSemantic3)
- trySemantic3(sc2);
-
- TemplateInstance *ti = tinst;
- int nest = 0;
- while (ti && !ti->deferred && ti->tinst)
- {
- ti = ti->tinst;
- if (++nest > global.recursionLimit)
- {
- global.gag = 0; // ensure error message gets printed
- error("recursive expansion");
- fatal();
- }
- }
- if (ti && ti->deferred)
- {
- //printf("deferred semantic3 of %p %s, ti = %s, ti->deferred = %p\n", this, toChars(), ti->toChars());
- for (size_t i = 0; ; i++)
- {
- if (i == ti->deferred->length)
- {
- ti->deferred->push(this);
- break;
- }
- if ((*ti->deferred)[i] == this)
- break;
- }
- }
- }
-
- if (aliasdecl)
- {
- /* Bugzilla 13816: AliasDeclaration tries to resolve forward reference
- * twice (See inuse check in AliasDeclaration::toAlias()). It's
- * necessary to resolve mutual references of instantiated symbols, but
- * it will left a true recursive alias in tuple declaration - an
- * AliasDeclaration A refers TupleDeclaration B, and B contains A
- * in its elements. To correctly make it an error, we strictly need to
- * resolve the alias of eponymous member.
- */
- aliasdecl = aliasdecl->toAlias2();
- }
-
- Laftersemantic:
- sc2->pop();
-
- scope->pop();
-
- // Give additional context info if error occurred during instantiation
- if (global.errors != errorsave)
- {
- if (!errors)
- {
- if (!tempdecl->literal)
- error(loc, "error instantiating");
- if (tinst)
- tinst->printInstantiationTrace();
- }
- errors = true;
- if (gagged)
- {
- // Errors are gagged, so remove the template instance from the
- // instance/symbol lists we added it to and reset our state to
- // finish clean and so we can try to instantiate it again later
- // (see bugzilla 4302 and 6602).
- tempdecl->removeInstance(tempdecl_instance_idx);
- if (target_symbol_list)
- {
- // Because we added 'this' in the last position above, we
- // should be able to remove it without messing other indices up.
- assert((*target_symbol_list)[target_symbol_list_idx] == this);
- target_symbol_list->remove(target_symbol_list_idx);
- memberOf = NULL; // no longer a member
- }
- semanticRun = PASSinit;
- inst = NULL;
- symtab = NULL;
- }
- }
- else if (errinst)
- {
- /* Bugzilla 14541: If the previous gagged instance had failed by
- * circular references, currrent "error reproduction instantiation"
- * might succeed, because of the difference of instantiated context.
- * On such case, the cached error instance needs to be overridden by the
- * succeeded instance.
- */
- //printf("replaceInstance()\n");
- TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)tempdecl->instances, (void *)hash);
- assert(tinstances);
- for (size_t i = 0; i < tinstances->length; i++)
- {
- TemplateInstance *ti = (*tinstances)[i];
- if (ti == errinst)
- {
- (*tinstances)[i] = this; // override
- break;
- }
- }
- }
-}
-
-
/**********************************************
* Find template declaration corresponding to template instance.
*
{
s = sc->search_correct(id);
if (s)
- error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars());
+ error("template `%s` is not defined, did you mean %s?", id->toChars(), s->toChars());
else
- error("template '%s' is not defined", id->toChars());
+ error("template `%s` is not defined", id->toChars());
return false;
}
{
// Try to fix forward reference. Ungag errors while doing so.
Ungag ungag = td->ungagSpeculative();
- td->semantic(td->_scope);
+ dsymbolSemantic(td, td->_scope);
}
if (td->semanticRun == PASSinit)
{
}
if (!s)
{
- error("template '%s' is not defined", id->toChars());
+ error("template `%s` is not defined", id->toChars());
return false;
}
}
//printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
if (flags & 1) // only used by __traits
{
- ea = ::semantic(ea, sc);
+ ea = expressionSemantic(ea, sc);
// must not interpret the args, excepting template parameters
if (ea->op != TOKvar ||
else
{
sc = sc->startCTFE();
- ea = ::semantic(ea, sc);
+ ea = expressionSemantic(ea, sc);
sc = sc->endCTFE();
if (ea->op == TOKvar)
TemplateDeclaration *td = sa->isTemplateDeclaration();
if (td && td->semanticRun == PASSinit && td->literal)
{
- td->semantic(sc);
+ dsymbolSemantic(td, sc);
}
FuncDeclaration *fd = sa->isFuncDeclaration();
if (fd)
{
// Try to fix forward reference. Ungag errors while doing so.
Ungag ungag = td->ungagSpeculative();
- td->semantic(td->_scope);
+ dsymbolSemantic(td, td->_scope);
}
if (td->semanticRun == PASSinit)
{
}
else
{
- error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars());
+ error("cannot use local `%s` as parameter to non-global template %s", sa->toChars(), tempdecl->toChars());
errors = true;
}
}
}
}
-void TemplateInstance::semantic2(Scope *sc)
-{
- if (semanticRun >= PASSsemantic2)
- return;
- semanticRun = PASSsemantic2;
- if (!errors && members)
- {
- TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- sc = tempdecl->_scope;
- assert(sc);
- sc = sc->push(argsym);
- sc = sc->push(this);
- sc->tinst = this;
- sc->minst = minst;
-
- int needGagging = (gagged && !global.gag);
- unsigned int olderrors = global.errors;
- int oldGaggedErrors = -1; // dead-store to prevent spurious warning
- if (needGagging)
- oldGaggedErrors = global.startGagging();
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic2(sc);
- if (gagged && global.errors != olderrors)
- break;
- }
-
- if (global.errors != olderrors)
- {
- if (!errors)
- {
- if (!tempdecl->literal)
- error(loc, "error instantiating");
- if (tinst)
- tinst->printInstantiationTrace();
- }
- errors = true;
- }
- if (needGagging)
- global.endGagging(oldGaggedErrors);
-
- sc = sc->pop();
- sc->pop();
- }
-}
-
-void TemplateInstance::semantic3(Scope *sc)
-{
-//if (toChars()[0] == 'D') *(char*)0=0;
- if (semanticRun >= PASSsemantic3)
- return;
- semanticRun = PASSsemantic3;
- if (!errors && members)
- {
- TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- sc = tempdecl->_scope;
- sc = sc->push(argsym);
- sc = sc->push(this);
- sc->tinst = this;
- sc->minst = minst;
-
- int needGagging = (gagged && !global.gag);
- unsigned int olderrors = global.errors;
- int oldGaggedErrors = -1; // dead-store to prevent spurious warning
- /* If this is a gagged instantiation, gag errors.
- * Future optimisation: If the results are actually needed, errors
- * would already be gagged, so we don't really need to run semantic
- * on the members.
- */
- if (needGagging)
- oldGaggedErrors = global.startGagging();
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic3(sc);
- if (gagged && global.errors != olderrors)
- break;
- }
-
- if (global.errors != olderrors)
- {
- if (!errors)
- {
- if (!tempdecl->literal)
- error(loc, "error instantiating");
- if (tinst)
- tinst->printInstantiationTrace();
- }
- errors = true;
- }
- if (needGagging)
- global.endGagging(oldGaggedErrors);
-
- sc = sc->pop();
- sc->pop();
- }
-}
-
/**************************************
* Given an error instantiating the TemplateInstance,
* give the nested TemplateInstance instantiations that got
// Maybe we can resolve it
if (_scope)
{
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
}
if (!inst)
{
if (td->semanticRun == PASSinit)
{
if (td->_scope)
- td->semantic(td->_scope);
+ dsymbolSemantic(td, td->_scope);
else
{
tm->semanticRun = PASSinit;
return true;
}
-void TemplateMixin::semantic(Scope *sc)
-{
- if (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;
- }
- semanticRun = PASSsemantic;
-
- Scope *scx = NULL;
- if (_scope)
- {
- sc = _scope;
- scx = _scope; // save so we don't make redundant copies
- _scope = NULL;
- }
-
- /* Run semantic on each argument, place results in tiargs[],
- * then find best match template with tiargs
- */
- if (!findTempDecl(sc) ||
- !semanticTiargs(sc) ||
- !findBestMatch(sc, NULL))
- {
- if (semanticRun == PASSinit) // forward reference had occured
- {
- //printf("forward reference - deferring\n");
- _scope = scx ? scx : sc->copy();
- _scope->setNoFree();
- _scope->_module->addDeferredSemantic(this);
- return;
- }
-
- inst = this;
- errors = true;
- return; // error recovery
- }
- TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- if (!ident)
- {
- /* Assign scope local unique identifier, as same as lambdas.
- */
- const char *s = "__mixin";
-
- DsymbolTable *symtab;
- if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
- {
- symtab = func->localsymtab;
- if (symtab)
- {
- // Inside template constraint, symtab is not set yet.
- goto L1;
- }
- }
- else
- {
- symtab = sc->parent->isScopeDsymbol()->symtab;
- L1:
- assert(symtab);
- int num = (int)dmd_aaLen(symtab->tab) + 1;
- ident = Identifier::generateId(s, num);
- symtab->insert(this);
- }
- }
-
- inst = this;
- parent = sc->parent;
-
- /* Detect recursive mixin instantiations.
- */
- for (Dsymbol *s = parent; s; s = s->parent)
- {
- //printf("\ts = '%s'\n", s->toChars());
- TemplateMixin *tm = s->isTemplateMixin();
- if (!tm || tempdecl != tm->tempdecl)
- continue;
-
- /* Different argument list lengths happen with variadic args
- */
- if (tiargs->length != tm->tiargs->length)
- continue;
-
- for (size_t i = 0; i < tiargs->length; i++)
- {
- RootObject *o = (*tiargs)[i];
- Type *ta = isType(o);
- Expression *ea = isExpression(o);
- Dsymbol *sa = isDsymbol(o);
- RootObject *tmo = (*tm->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);
- }
- error("recursive mixin instantiation");
- return;
-
- Lcontinue:
- continue;
- }
-
- // Copy the syntax trees from the TemplateDeclaration
- members = Dsymbol::arraySyntaxCopy(tempdecl->members);
- if (!members)
- return;
-
- symtab = new DsymbolTable();
-
- for (Scope *sce = sc; 1; sce = sce->enclosing)
- {
- ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
- if (sds)
- {
- sds->importScope(this, Prot(Prot::public_));
- break;
- }
- }
-
- Scope *scy = sc->push(this);
- scy->parent = this;
-
- argsym = new ScopeDsymbol();
- argsym->parent = scy->parent;
- Scope *argscope = scy->push(argsym);
-
- unsigned errorsave = global.errors;
-
- // Declare each template parameter as an alias for the argument type
- declareParameters(argscope);
-
- // Add members to enclosing scope, as well as this scope
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->addMember(argscope, this);
- //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(this);
- //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
- error("recursive expansion");
- fatal();
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->setScope(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->importAll(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic(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 = toParent()->isAggregateDeclaration();
- if (sc->func && !ad)
- {
- semantic2(sc2);
- semantic3(sc2);
- }
-
- // Give additional context info if error occurred during instantiation
- if (global.errors != errorsave)
- {
- error("error instantiating");
- errors = true;
- }
-
- sc2->pop();
- argscope->pop();
- scy->pop();
-}
-
-void TemplateMixin::semantic2(Scope *sc)
-{
- if (semanticRun >= PASSsemantic2)
- return;
- semanticRun = PASSsemantic2;
- if (members)
- {
- assert(sc);
- sc = sc->push(argsym);
- sc = sc->push(this);
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic2(sc);
- }
- sc = sc->pop();
- sc->pop();
- }
-}
-
-void TemplateMixin::semantic3(Scope *sc)
-{
- if (semanticRun >= PASSsemantic3)
- return;
- semanticRun = PASSsemantic3;
- if (members)
- {
- sc = sc->push(argsym);
- sc = sc->push(this);
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic3(sc);
- }
- sc = sc->pop();
- sc->pop();
- }
-}
-
const char *TemplateMixin::kind() const
{
return "mixin";
int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param)
{
if (_scope) // if fwd reference
- semantic(NULL); // try to resolve it
+ dsymbolSemantic(this, NULL); // try to resolve it
if (members)
{
for (size_t i = 0; i < members->length; i++)
{
//printf("TemplateMixin::setFieldOffset() %s\n", toChars());
if (_scope) // if fwd reference
- semantic(NULL); // try to resolve it
+ dsymbolSemantic(this, NULL); // try to resolve it
if (members)
{
for (size_t i = 0; i < members->length; i++)
/* 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.
}
}
-void DebugSymbol::semantic(Scope *)
-{
- //printf("DebugSymbol::semantic() %s\n", toChars());
- if (semanticRun < PASSsemanticdone)
- semanticRun = PASSsemanticdone;
-}
-
const char *DebugSymbol::kind() const
{
return "debug";
}
}
-void VersionSymbol::semantic(Scope *)
-{
- if (semanticRun < PASSsemanticdone)
- semanticRun = PASSsemanticdone;
-}
-
const char *VersionSymbol::kind() const
{
return "version";
/* 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.
/* 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.
Dsymbol *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
- void semantic(Scope *sc);
bool oneMember(Dsymbol **ps, Identifier *ident);
Type *getType();
const char *kind() const;
StorageClass stc, UserAttributeDeclaration *uad, DeprecatedDeclaration *dd);
Dsymbol *syntaxCopy(Dsymbol *s);
const char *kind() const;
- void semantic(Scope *sc);
Expression *getVarExp(Loc loc, Scope *sc);
EnumMember *isEnumMember() { return this; }
/* 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.
/* 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.
/* 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.
bool MODimplicitConv(MOD modfrom, MOD modto);
MOD MODmerge(MOD mod1, MOD mod2);
void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
-Expression *trySemantic(Expression *e, Scope *sc);
-Expression *semantic(Expression *e, Scope *sc);
-Expression *semanticX(DotIdExp *exp, Scope *sc);
-Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
-Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
e1->type = tcd->vthis->type;
e1->type = e1->type->addMod(t->mod);
// Do not call checkNestedRef()
- //e1 = semantic(e1, sc);
+ //e1 = expressionSemantic(e1, sc);
// Skip up over nested functions, and get the enclosing
// class type.
}
else
{
- e1->error("need 'this' of type %s to access member %s"
+ e1->error("need `this` of type %s to access member %s"
" from static function %s",
ad->toChars(), var->toChars(), f->toChars());
e1 = new ErrorExp();
e1->type = s->isClassDeclaration()->type;
e1->type = e1->type->addMod(t->mod);
if (n > 1)
- e1 = semantic(e1, sc);
+ e1 = expressionSemantic(e1, sc);
}
else
- e1 = semantic(e1, sc);
+ e1 = expressionSemantic(e1, sc);
goto L1;
}
FuncDeclaration *fd = NULL;
if (e2)
{
- e2 = semantic(e2, sc);
+ e2 = expressionSemantic(e2, sc);
if (e2->op == TOKerror)
return new ErrorExp();
e2 = resolveProperties(sc, e2);
if (fd)
{
Expression *e = new CallExp(loc, e1, e2);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
}
{
Expression *e = new CallExp(loc, e1);
if (e2)
e = new AssignExp(loc, e, e2);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
}
if (e2)
assert(s);
if (e2)
{
- e2 = semantic(e2, sc);
+ e2 = expressionSemantic(e2, sc);
if (e2->op == TOKerror)
return new ErrorExp();
e2 = resolveProperties(sc, e2);
return new ErrorExp();
assert(fd->type->ty == Tfunction);
Expression *e = new CallExp(loc, e1, e2);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
}
{
Expression *e = new CallExp(loc, e1);
if (e2)
e = new AssignExp(loc, e, e2);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
}
}
// Keep better diagnostic message for invalid property usage of functions
assert(fd->type->ty == Tfunction);
Expression *e = new CallExp(loc, e1, e2);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
if (e2)
goto Leprop;
if (ve->var->storage_class & STClazy)
{
Expression *e = new CallExp(loc, e1);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
}
else if (e1->op == TOKdotvar)
*/
if (!tf->deco && ce->f->semanticRun < PASSsemanticdone)
{
- ce->f->semantic(NULL);
+ dsymbolSemantic(ce->f, NULL);
tf = (TypeFunction *)ce->f->type;
}
}
return new ErrorExp();
}
Expression *key = (*ce->arguments)[0];
- key = semantic(key, sc);
+ key = expressionSemantic(key, sc);
key = resolveProperties(sc, key);
TypeAArray *taa = (TypeAArray *)t;
if (isDotOpDispatch(ey))
{
unsigned errors = global.startGagging();
- e = semantic(ce->syntaxCopy(), sc);
+ e = expressionSemantic(ce->syntaxCopy(), sc);
if (!global.endGagging(errors))
return e;
/* fall down to UFCS */
if (e2)
{
// run semantic without gagging
- e2 = semantic(e2, sc);
+ e2 = expressionSemantic(e2, sc);
/* f(e1) = e2
*/
if (!e)
{ checkPropertyCall(ex);
ex = new AssignExp(loc, ex, e2);
- return semantic(ex, sc);
+ return expressionSemantic(ex, sc);
}
}
else
{ // strict setter prints errors if fails
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
checkPropertyCall(e);
return e;
arguments->setDim(1);
(*arguments)[0] = eleft;
e = new CallExp(loc, e, arguments);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
checkPropertyCall(e);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
}
Expression *e = (*exps)[i];
if (e)
{
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (e->op == TOKerror)
err = true;
if (preserveErrors || e->op != TOKerror)
condexp.e1 = e0;
condexp.e2 = e;
condexp.loc = e->loc;
- Expression *ex = semantic(&condexp, sc);
+ Expression *ex = expressionSemantic(&condexp, sc);
if (ex->op == TOKerror)
e = ex;
else
*/
VarDeclaration *tmp = copyToTemp(STCrvalue, "__copytmp", e);
tmp->storage_class |= STCnodtor;
- tmp->semantic(sc);
+ dsymbolSemantic(tmp, sc);
Expression *de = new DeclarationExp(e->loc, tmp);
Expression *ve = new VarExp(e->loc, tmp);
de->type = Type::tvoid;
}
break;
}
- arg = semantic(arg, sc);
+ arg = expressionSemantic(arg, sc);
//printf("\targ = '%s'\n", arg->toChars());
arguments->setDim(i + 1);
(*arguments)[i] = arg;
Identifier *idtmp = Identifier::generateId("__gate");
gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
gate->storage_class |= STCtemp | STCctfe | STCvolatile;
- gate->semantic(sc);
+ dsymbolSemantic(gate, sc);
Expression *ae = new DeclarationExp(loc, gate);
- eprefix = semantic(ae, sc);
+ eprefix = expressionSemantic(ae, sc);
}
for (ptrdiff_t i = start; i != end; i += step)
VarDeclaration *tmp = copyToTemp(0,
needsDtor ? "__pfx" : "__pfy",
!isRef ? arg : arg->addressOf());
- tmp->semantic(sc);
+ dsymbolSemantic(tmp, sc);
/* Modify the destructor so it only runs if gate==false, i.e.,
* only if there was a throw while constructing the args
assert(tmp->edtor);
Expression *e = tmp->edtor;
e = new LogicalExp(e->loc, TOKoror, new VarExp(e->loc, gate), e);
- tmp->edtor = semantic(e, sc);
+ tmp->edtor = expressionSemantic(e, sc);
//printf("edtor: %s\n", tmp->edtor->toChars());
}
// eprefix => (eprefix, auto __pfx/y = arg)
DeclarationExp *ae = new DeclarationExp(loc, tmp);
- eprefix = Expression::combine(eprefix, semantic(ae, sc));
+ eprefix = Expression::combine(eprefix, expressionSemantic(ae, sc));
// arg => __pfx/y
arg = new VarExp(loc, tmp);
- arg = semantic(arg, sc);
+ arg = expressionSemantic(arg, sc);
if (isRef)
{
arg = new PtrExp(loc, arg);
- arg = semantic(arg, sc);
+ arg = expressionSemantic(arg, sc);
}
/* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
if (i == lastthrow)
{
Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
- eprefix = Expression::combine(eprefix, semantic(e, sc));
+ eprefix = Expression::combine(eprefix, expressionSemantic(e, sc));
gate = NULL;
}
}
TypeTuple *tup = new TypeTuple(args);
Expression *e = new TypeidExp(loc, tup);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
arguments->insert(0, e);
}
loc = e->loc;
if (e->op == TOKtype)
- error("%s '%s' is a type, not an lvalue", e->type->kind(), e->type->toChars());
+ error("%s `%s` is a type, not an lvalue", e->type->kind(), e->type->toChars());
else
error("%s is not an lvalue", e->toChars());
return true;
if (!type->isscalar())
{
- error("'%s' is not a scalar, it is a %s", toChars(), type->toChars());
+ error("`%s` is not a scalar, it is a %s", toChars(), type->toChars());
return true;
}
return checkValue();
return true;
if (type->toBasetype()->ty == Tbool)
{
- error("operation not allowed on bool '%s'", toChars());
+ error("operation not allowed on bool `%s`", toChars());
return true;
}
return false;
return true;
if (!type->isintegral())
{
- error("'%s' is not of integral type, it is a %s", toChars(), type->toChars());
+ error("`%s` is not of integral type, it is a %s", toChars(), type->toChars());
return true;
}
return checkValue();
return true;
if (!type->isintegral() && !type->isfloating())
{
- error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars());
+ error("`%s` is not of arithmetic type, it is a %s", toChars(), type->toChars());
return true;
}
return checkValue();
FuncDeclaration *ff = outerfunc;
if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
{
- error("pure %s '%s' cannot call impure %s '%s'",
+ error("pure %s `%s` cannot call impure %s `%s`",
ff->kind(), ff->toPrettyChars(), f->kind(), f->toPrettyChars());
return true;
}
break;
if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
{
- error("pure %s '%s' cannot access mutable static data '%s'",
+ error("pure %s `%s` cannot access mutable static data `%s`",
ff->kind(), ff->toPrettyChars(), v->toChars());
err = true;
break;
OutBuffer vbuf;
MODMatchToBuffer(&ffbuf, ff->type->mod, v->type->mod);
MODMatchToBuffer(&vbuf, v->type->mod, ff->type->mod);
- error("%s%s '%s' cannot access %sdata '%s'",
+ error("%s%s `%s` cannot access %sdata `%s`",
ffbuf.peekChars(), ff->kind(), ff->toPrettyChars(), vbuf.peekChars(), v->toChars());
err = true;
break;
{
if (sc->func->setUnsafe())
{
- error("safe %s '%s' cannot access __gshared data '%s'",
+ error("safe %s `%s` cannot access __gshared data `%s`",
sc->func->kind(), sc->func->toChars(), v->toChars());
err = true;
}
if (loc.linnum == 0) // e.g. implicitly generated dtor
loc = sc->func->loc;
- error("@safe %s '%s' cannot call @system %s '%s'",
+ error("@safe %s `%s` cannot call @system %s `%s`",
sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
return true;
}
if (loc.linnum == 0) // e.g. implicitly generated dtor
loc = sc->func->loc;
- error("@nogc %s '%s' cannot call non-@nogc %s '%s'",
+ error("@nogc %s `%s` cannot call non-@nogc %s `%s`",
sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
return true;
}
{
//printf("checkRightThis sc->intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
// sc->intypeof, sc->getStructClassScope(), func, fdthis);
- error("need 'this' for '%s' of type '%s'", ve->var->toChars(), ve->var->type->toChars());
+ error("need `this` for `%s` of type `%s`", ve->var->toChars(), ve->var->type->toChars());
return true;
}
}
if (fd)
{
e = new CastExp(loc, e, Type::tbool);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
(!v->type->deco && v->inuse)) // during variable type semantic
{
if (v->inuse) // variable type depends on the variable itself
- ::error(loc, "circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ ::error(loc, "circular reference to %s `%s`", v->kind(), v->toPrettyChars());
else // variable type cannot be determined
- ::error(loc, "forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ ::error(loc, "forward reference to %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
if (v->type->ty == Terror)
{
if (v->inuse)
{
- ::error(loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ ::error(loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
e = v->expandInitializer(loc);
v->inuse++;
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
v->inuse--;
return e;
}
e = new DotVarExp(loc, new ThisExp(loc), v);
else
e = new VarExp(loc, v);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
{
//printf("'%s' is a function literal\n", fld->toChars());
e = new FuncExp(loc, fld);
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
if (FuncDeclaration *f = s->isFuncDeclaration())
{
return new ErrorExp();
}
ScopeExp *ie = new ScopeExp(loc, imp->pkg);
- return semantic(ie, sc);
+ return expressionSemantic(ie, sc);
}
if (Package *pkg = s->isPackage())
{
ScopeExp *ie = new ScopeExp(loc, pkg);
- return semantic(ie, sc);
+ return expressionSemantic(ie, sc);
}
if (Module *mod = s->isModule())
{
ScopeExp *ie = new ScopeExp(loc, mod);
- return semantic(ie, sc);
+ return expressionSemantic(ie, sc);
}
if (Nspace *ns = s->isNspace())
{
ScopeExp *ie = new ScopeExp(loc, ns);
- return semantic(ie, sc);
+ return expressionSemantic(ie, sc);
}
if (Type *t = s->getType())
{
- return semantic(new TypeExp(loc, t), sc);
+ return expressionSemantic(new TypeExp(loc, t), sc);
}
if (TupleDeclaration *tup = s->isTupleDeclaration())
e = new DotVarExp(loc, new ThisExp(loc), tup);
else
e = new TupleExp(loc, tup);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (TemplateInstance *ti = s->isTemplateInstance())
{
- ti->semantic(sc);
+ dsymbolSemantic(ti, sc);
if (!ti->inst || ti->errors)
return new ErrorExp();
s = ti->toAlias();
if (!s->isTemplateInstance())
goto Lagain;
e = new ScopeExp(loc, ti);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (TemplateDeclaration *td = s->isTemplateDeclaration())
}
else
e = new TemplateExp(loc, td);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
- ::error(loc, "%s '%s' is not a variable", s->kind(), s->toChars());
+ ::error(loc, "%s `%s` is not a variable", s->kind(), s->toChars());
return new ErrorExp();
}
VarDeclaration *tmp = copyToTemp(0, buf, this);
Expression *ae = new DeclarationExp(loc, tmp);
Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
return this;
// FIXME: This error report will never be handled anyone.
// It should be done before the SymOffExp construction.
if (v->needThis())
- ::error(loc, "need 'this' for address of %s", v->toChars());
+ ::error(loc, "need `this` for address of %s", v->toChars());
}
this->offset = offset;
}
{
if (var->storage_class & STCmanifest)
{
- error("manifest constant '%s' is not lvalue", var->toChars());
+ error("manifest constant `%s` is not lvalue", var->toChars());
return new ErrorExp();
}
if (var->storage_class & STClazy)
}
if (var->ident == Id::dollar) // Bugzilla 13574
{
- error("'$' is not an lvalue");
+ error("`$` is not an lvalue");
return new ErrorExp();
}
return this;
//printf("VarExp::modifiableLvalue('%s')\n", var->toChars());
if (var->storage_class & STCmanifest)
{
- error("cannot modify manifest constant '%s'", toChars());
+ error("cannot modify manifest constant `%s`", toChars());
return new ErrorExp();
}
// See if this expression is a modifiable lvalue (i.e. not const)
if (tok == TOKfunction)
{
if (!flag)
- error("cannot match function literal to delegate type '%s'", to->toChars());
+ error("cannot match function literal to delegate type `%s`", to->toChars());
return MATCHnomatch;
}
tof = (TypeFunction *)to->nextOf();
if (tok == TOKdelegate)
{
if (!flag)
- error("cannot match delegate literal to function pointer type '%s'", to->toChars());
+ error("cannot match delegate literal to function pointer type `%s`", to->toChars());
return MATCHnomatch;
}
tof = (TypeFunction *)to->nextOf();
TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
Expression *ex = new ScopeExp(loc, ti);
- ex = ::semantic(ex, td->_scope);
+ ex = expressionSemantic(ex, td->_scope);
// Reset inference target for the later re-semantic
fd->treq = NULL;
if (e1->op == TOKtype)
{
- error("incompatible type for (%s(%s)): cannot use '%s' with types",
+ error("incompatible type for (%s(%s)): cannot use `%s` with types",
Token::toChars(op), e1->toChars(), Token::toChars(op));
}
else
{
- error("incompatible type for (%s(%s)): '%s'",
+ error("incompatible type for (%s(%s)): `%s`",
Token::toChars(op), e1->toChars(), e1->type->toChars());
}
return new ErrorExp();
TOK thisOp = (op == TOKquestion) ? TOKcolon : op;
if (e1->op == TOKtype || e2->op == TOKtype)
{
- error("incompatible types for ((%s) %s (%s)): cannot use '%s' with types",
+ error("incompatible types for ((%s) %s (%s)): cannot use `%s` with types",
e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op));
}
else
{
- error("incompatible types for ((%s) %s (%s)): '%s' and '%s'",
+ error("incompatible types for ((%s) %s (%s)): `%s` and `%s`",
e1->toChars(), Token::toChars(thisOp), e2->toChars(),
e1->type->toChars(), e2->type->toChars());
}
else
{
const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
- ::error(loc, "%s field '%s' initialized multiple times", modStr, var->toChars());
+ ::error(loc, "%s field `%s` initialized multiple times", modStr, var->toChars());
}
}
else if (sc->noctor || (fi & CSXlabel))
else
{
const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
- ::error(loc, "%s field '%s' initialization is not allowed in loops or after labels", modStr, var->toChars());
+ ::error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var->toChars());
}
}
sc->fieldinit[i] |= CSXthis_ctor;
else if (sc->func->fes)
{
const char *p = var->isField() ? "field" : var->kind();
- ::error(loc, "%s %s '%s' initialization is not allowed in foreach loop",
+ ::error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
MODtoChars(var->type->mod), p, var->toChars());
}
else
{
const char *p = var->isField() ? "field" : var->kind();
- ::error(loc, "%s %s '%s' initialization is not allowed in nested function '%s'",
+ ::error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
MODtoChars(var->type->mod), p, var->toChars(), sc->func->toChars());
}
}
return true;
Expression *e = new DotIdExp(loc, e1, ti->name);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (e->op == TOKdot)
e = ((DotExp *)e)->e2;
DeclarationExp *de = new DeclarationExp(loc, tmp);
VarExp *ve = new VarExp(loc, tmp);
Expression *e = new CommaExp(loc, de, ve);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
}
if (!vcond)
{
vcond = copyToTemp(STCvolatile, "__cond", ce->econd);
- vcond->semantic(sc);
+ dsymbolSemantic(vcond, sc);
Expression *de = new DeclarationExp(ce->econd->loc, vcond);
- de = semantic(de, sc);
+ de = expressionSemantic(de, sc);
Expression *ve = new VarExp(ce->econd->loc, vcond);
ce->econd = Expression::combine(de, ve);
v->edtor = new LogicalExp(v->edtor->loc, TOKandand, ve, v->edtor);
else
v->edtor = new LogicalExp(v->edtor->loc, TOKoror, ve, v->edtor);
- v->edtor = semantic(v->edtor, sc);
+ v->edtor = expressionSemantic(v->edtor, sc);
//printf("\t--v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
}
}
s = loc.filename != NULL ? loc.filename : sc->_module->ident->toChars();
Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = e->castTo(sc, type);
return e;
}
else
s = sc->_module->toPrettyChars();
Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = e->castTo(sc, type);
return e;
}
else
s = "";
Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = e->castTo(sc, type);
return e;
}
}
Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = e->castTo(sc, type);
return e;
}
ae->lengthVar = NULL; // Create it only if required
ae->currentDimension = i; // Dimension for $, if required
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
if (ae->lengthVar && sc->func)
{
// If $ was used, declare it now
Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = semantic(de, sc);
+ de = expressionSemantic(de, sc);
*pe0 = Expression::combine(*pe0, de);
}
sc = sc->pop();
Objects *tiargs = new Objects();
Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
- edim = semantic(edim, sc);
+ edim = expressionSemantic(edim, sc);
tiargs->push(edim);
Expressions *fargs = new Expressions();
e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
e = new CallExp(ae->loc, e, fargs);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
if (!e->type)
StringExp *semanticString(Scope *sc, Expression *exp, const char *s)
{
sc = sc->startCTFE();
- exp = semantic(exp, sc);
+ exp = expressionSemantic(exp, sc);
exp = resolveProperties(sc, exp);
sc = sc->endCTFE();
for (size_t i = 0; i < 2; ++i)
{
Expression *e = i == 0 ? ie->lwr : ie->upr;
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
if (!e->type)
{
{
// If $ was used, declare it now
Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = semantic(de, sc);
+ de = expressionSemantic(de, sc);
*pe0 = Expression::combine(*pe0, de);
}
sc = sc->pop();
/* 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.
class TemplateDeclaration;
class ClassDeclaration;
class BinExp;
+class UnaExp;
+class DotIdExp;
+class DotTemplateInstanceExp;
class OverloadSet;
class Initializer;
class StringExp;
struct Symbol; // back end symbol
#endif
+Expression *expressionSemantic(Expression *e, Scope *sc);
+Expression *semanticX(DotIdExp *exp, Scope *sc);
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *unaSemantic(UnaExp *e, Scope *sc);
+Expression *binSemantic(BinExp *e, Scope *sc);
+Expression *binSemanticProp(BinExp *e, Scope *sc);
+StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
+
Expression *resolveProperties(Scope *sc, Expression *e);
Expression *resolvePropertiesOnly(Scope *sc, Expression *e1);
bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d);
/* 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.
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL);
Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL);
-Expression *trySemantic(Expression *e, Scope *sc);
-Expression *unaSemantic(UnaExp *e, Scope *sc);
-Expression *binSemantic(BinExp *e, Scope *sc);
-Expression *binSemanticProp(BinExp *e, Scope *sc);
-Expression *semantic(Expression *e, Scope *sc);
-Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
-Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
-Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
/****************************************
* Preprocess arguments to function.
void visit(Expression *e)
{
if (e->type)
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
else
e->type = Type::tvoid;
result = e;
if (!e->type)
e->type = Type::tfloat64;
else
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
result = e;
}
if (!e->type)
e->type = Type::tcomplex80;
else
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
result = e;
}
// The redudancy should be removed.
e = new VarExp(exp->loc, withsym->withstate->wthis);
e = new DotIdExp(exp->loc, e, exp->ident);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
else
{
e = withsym->withstate->exp;
}
e = new DotIdExp(exp->loc, e, exp->ident);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
td = td->overroot; // then get the start
e = new TemplateExp(exp->loc, td, f);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
vd->storage_class |= STCtemp;
vd->semanticRun = PASSsemanticdone;
Expression *e = new VarExp(exp->loc, vd);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
return;
Lerr:
- e->error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars());
+ e->error("`this` is only defined in non-static member functions, not %s", sc->parent->toChars());
return setError();
}
cd = cd->baseClass;
if (!cd)
{
- e->error("class %s has no 'super'", s->toChars());
+ e->error("class %s has no `super`", s->toChars());
goto Lerr;
}
e->type = cd->type;
return;
Lerr:
- e->error("'super' is only allowed in non-static class member functions");
+ e->error("`super` is only allowed in non-static class member functions");
return setError();
}
e->type = new TypeDArray(Type::tchar->immutableOf());
break;
}
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
//e->type = e->type->immutableOf();
//printf("type = %s\n", e->type->toChars());
*/
if (e->basis)
- e->basis = semantic(e->basis, sc);
+ e->basis = expressionSemantic(e->basis, sc);
if (arrayExpressionSemantic(e->elements, sc) || (e->basis && e->basis->op == TOKerror))
return setError();
expandTuples(e->elements);
return setError();
e->type = t0->arrayOf();
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
/* Disallow array literals of type void being used.
*/
return setError();
e->type = new TypeAArray(tvalue, tkey);
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
semanticTypeInfo(sc, e->type);
e = new DotVarExp(exp->loc, new ThisExp(exp->loc), ve->var, false);
}
//printf("e = %s %s\n", Token::toChars(e->op), e->toChars());
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
else if (t)
{
//printf("t = %d %s\n", t->ty, t->toChars());
- exp->type = t->semantic(exp->loc, sc);
+ exp->type = typeSemantic(t, exp->loc, sc);
e = exp;
}
else if (s)
{
Expression *e = new VarExp(exp->loc, withsym->withstate->wthis);
e = new DotTemplateInstanceExp(exp->loc, e, ti);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
if (ti->needsTypeInference(sc))
(td->_scope->stc & STCstatic) == 0)
{
Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
}
if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad)
{
Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
}
result = exp;
return;
}
- ti->semantic(sc);
+ dsymbolSemantic(ti, sc);
if (!ti->inst || ti->errors)
return setError();
*/
if (ti->inuse)
{
- exp->error("recursive expansion of %s '%s'", ti->kind(), ti->toPrettyChars());
+ exp->error("recursive expansion of %s `%s`", ti->kind(), ti->toPrettyChars());
return setError();
}
Expression *e = v->expandInitializer(exp->loc);
ti->inuse++;
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
ti->inuse--;
result = e;
return;
//printf("sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
//printf("\tparent = '%s'\n", sds2->parent->toChars());
- sds2->semantic(sc);
+ dsymbolSemantic(sds2, sc);
if (Type *t = sds2->getType()) // (Aggregate|Enum)Declaration
{
Expression *ex = new TypeExp(exp->loc, t);
- result = semantic(ex, sc);
+ result = expressionSemantic(ex, sc);
return;
}
if (TemplateDeclaration *td = sds2->isTemplateDeclaration())
{
- result = semantic(new TemplateExp(exp->loc, td), sc);
+ result = expressionSemantic(new TemplateExp(exp->loc, td), sc);
return;
}
ClassDeclaration *cdthis = NULL;
if (exp->thisexp)
{
- exp->thisexp = semantic(exp->thisexp, sc);
+ exp->thisexp = expressionSemantic(exp->thisexp, sc);
if (exp->thisexp->op == TOKerror)
return setError();
cdthis = exp->thisexp->type->isClassHandle();
if (!cdthis)
{
- exp->error("'this' for nested class must be a class type, not %s", exp->thisexp->type->toChars());
+ exp->error("`this` for nested class must be a class type, not %s", exp->thisexp->type->toChars());
return setError();
}
sc = sc->push(cdthis);
- exp->type = exp->newtype->semantic(exp->loc, sc);
+ exp->type = typeSemantic(exp->newtype, exp->loc, sc);
sc = sc->pop();
}
else
{
- exp->type = exp->newtype->semantic(exp->loc, sc);
+ exp->type = typeSemantic(exp->newtype, exp->loc, sc);
}
if (exp->type->ty == Terror)
return setError();
{
// --> new T[edim]
exp->type = new TypeSArray(exp->type, edim);
- exp->type = exp->type->semantic(exp->loc, sc);
+ exp->type = typeSemantic(exp->type, exp->loc, sc);
if (exp->type->ty == Terror)
return setError();
}
{
FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration();
if (fd && fd->isAbstract())
- errorSupplemental(exp->loc, "function '%s' is not implemented", fd->toFullSignature());
+ errorSupplemental(exp->loc, "function `%s` is not implemented", fd->toFullSignature());
}
return setError();
}
{
if (!sp)
{
- exp->error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars());
+ exp->error("outer class %s `this` needed to `new` nested class %s", cdn->toChars(), cd->toChars());
return setError();
}
ClassDeclaration *cdp = sp->isClassDeclaration();
// Add a '.outer' and try again
exp->thisexp = new DotIdExp(exp->loc, exp->thisexp, Id::outer);
}
- exp->thisexp = semantic(exp->thisexp, sc);
+ exp->thisexp = expressionSemantic(exp->thisexp, sc);
if (exp->thisexp->op == TOKerror)
return setError();
cdthis = exp->thisexp->type->isClassHandle();
if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL))
{
//printf("cdthis = %s\n", cdthis->toChars());
- exp->error("'this' for nested class must be of type %s, not %s",
+ exp->error("`this` for nested class must be of type %s, not %s",
cdn->toChars(), exp->thisexp->type->toChars());
return setError();
}
// make sure the parent context fdn of cd is reachable from sc
if (checkNestedRef(sc->parent, fdn))
{
- exp->error("outer function context of %s is needed to 'new' nested class %s",
+ exp->error("outer function context of %s is needed to `new` nested class %s",
fdn->toPrettyChars(), cd->toPrettyChars());
return setError();
}
v->_init->isVoidInitializer())
continue;
v->inuse++;
- v->_init = semantic(v->_init, v->_scope, v->type, INITinterpret);
+ v->_init = initializerSemantic(v->_init, v->_scope, v->type, INITinterpret);
v->inuse--;
}
}
Expression *d = new DeclarationExp(e->loc, e->cd);
sc = sc->push(); // just create new scope
sc->flags &= ~SCOPEctfe; // temporary stop CTFE
- d = semantic(d, sc);
+ d = expressionSemantic(d, sc);
sc = sc->pop();
if (!e->cd->errors && sc->intypeof && !sc->parent->inNonRoot())
Expression *n = new NewExp(e->loc, e->thisexp, e->newargs, e->cd->type, e->arguments);
Expression *c = new CommaExp(e->loc, d, n);
- result = semantic(c, sc);
+ result = expressionSemantic(c, sc);
}
void visit(SymOffExp *e)
{
- //var->semantic(sc);
+ //dsymbolSemantic(var, sc);
if (!e->type)
e->type = e->var->type->pointerTo();
if (VarDeclaration *v = e->var->isVarDeclaration())
Declaration *decl = e->var->isDeclaration();
if (decl)
decl->inuse++;
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
if (decl)
decl->inuse--;
}
}
if (exp->e0)
- exp->e0 = semantic(exp->e0, sc);
+ exp->e0 = expressionSemantic(exp->e0, sc);
// Run semantic() on each argument
bool err = false;
for (size_t i = 0; i < exp->exps->length; i++)
{
Expression *e = (*exp->exps)[i];
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (!e->type)
{
exp->error("%s has no value", e->toChars());
expandTuples(exp->exps);
exp->type = new TypeTuple(exp->exps);
- exp->type = exp->type->semantic(exp->loc, sc);
+ exp->type = typeSemantic(exp->type, exp->loc, sc);
//printf("-TupleExp::semantic(%s)\n", exp->toChars());
result = exp;
}
* foo(a=>a); // in IFTI, treq == T delegate(int)
*/
//if (exp->fd->treq)
- // exp->fd->treq = exp->fd->treq->semantic(exp->loc, sc);
+ // exp->fd->treq = typeSemantic(exp->fd->treq, exp->loc, sc);
exp->genIdent(sc);
if (exp->td)
{
assert(exp->td->parameters && exp->td->parameters->length);
- exp->td->semantic(sc);
+ dsymbolSemantic(exp->td, sc);
exp->type = Type::tvoid; // temporary type
if (exp->fd->treq) // defer type determination
}
unsigned olderrors = global.errors;
- exp->fd->semantic(sc);
+ dsymbolSemantic(exp->fd, sc);
if (olderrors == global.errors)
{
- exp->fd->semantic2(sc);
+ semantic2(exp->fd, sc);
if (olderrors == global.errors)
- exp->fd->semantic3(sc);
+ semantic3(exp->fd, sc);
}
if (olderrors != global.errors)
{
(exp->tok == TOKreserved && exp->fd->treq && exp->fd->treq->ty == Tdelegate))
{
exp->type = new TypeDelegate(exp->fd->type);
- exp->type = exp->type->semantic(exp->loc, sc);
+ exp->type = typeSemantic(exp->type, exp->loc, sc);
exp->fd->tok = TOKdelegate;
}
else
{
exp->type = new TypePointer(exp->fd->type);
- exp->type = exp->type->semantic(exp->loc, sc);
+ exp->type = typeSemantic(exp->type, exp->loc, sc);
//exp->type = exp->fd->type->pointerTo();
/* A lambda expression deduced to function pointer might become
exp->genIdent(sc);
assert(exp->td->parameters && exp->td->parameters->length);
- exp->td->semantic(sc);
+ dsymbolSemantic(exp->td, sc);
TypeFunction *tfl = (TypeFunction *)exp->fd->type;
size_t dim = tfl->parameterList.length();
TemplateInstance *ti = new TemplateInstance(exp->loc, exp->td, tiargs);
Expression *se = new ScopeExp(exp->loc, ti);
- return semantic(se, sc);
+ return expressionSemantic(se, sc);
}
exp->error("cannot infer function literal type");
return new ErrorExp();
}
- return semantic(exp, sc);
+ return expressionSemantic(exp, sc);
}
void visit(DeclarationExp *e)
// Do semantic() on initializer first, so:
// int a = a;
// will be illegal.
- e->declaration->semantic(sc);
+ dsymbolSemantic(e->declaration, sc);
s->parent = sc->parent;
}
if (sc2->stc & (STCpure | STCnothrow | STCnogc))
sc2 = sc->push();
sc2->stc &= ~(STCpure | STCnothrow | STCnogc);
- e->declaration->semantic(sc2);
+ dsymbolSemantic(e->declaration, sc2);
if (sc2 != sc)
sc2->pop();
s->parent = sc->parent;
}
if (global.errors == olderrors)
{
- e->declaration->semantic2(sc);
+ semantic2(e->declaration, sc);
if (global.errors == olderrors)
{
- e->declaration->semantic3(sc);
+ semantic3(e->declaration, sc);
}
}
// todo: error in declaration should be propagated.
if (Dsymbol *sym = getDsymbol(ea))
ea = resolve(exp->loc, sc, sym, false);
else
- ea = semantic(ea, sc);
+ ea = expressionSemantic(ea, sc);
ea = resolveProperties(sc, ea);
ta = ea->type;
if (ea->op == TOKtype)
{
/* Get the dynamic type, which is .classinfo
*/
- ea = semantic(ea, sc);
+ ea = expressionSemantic(ea, sc);
e = new TypeidExp(ea->loc, ea);
e->type = Type::typeinfoclass->type;
}
if (ea)
{
e = new CommaExp(exp->loc, ea, e); // execute ea
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
}
result = e;
Parameters *args = new Parameters;
args->reserve(cd->baseclasses->length);
if (cd->semanticRun < PASSsemanticdone)
- cd->semantic(NULL);
+ dsymbolSemantic(cd, NULL);
for (size_t i = 0; i < cd->baseclasses->length; i++)
{
BaseClass *b = (*cd->baseclasses)[i];
* is(targ == tspec)
* is(targ : tspec)
*/
- e->tspec = e->tspec->semantic(e->loc, sc);
+ e->tspec = typeSemantic(e->tspec, e->loc, sc);
//printf("targ = %s, %s\n", e->targ->toChars(), e->targ->deco);
//printf("tspec = %s, %s\n", e->tspec->toChars(), e->tspec->deco);
if (e->tok == TOKcolon)
m = tp->matchArg(e->loc, sc, &tiargs, i, e->parameters, &dedtypes, &s);
if (m <= MATCHnomatch)
goto Lno;
- s->semantic(sc);
+ dsymbolSemantic(s, sc);
if (!sc->insert(s))
e->error("declaration %s is already defined", s->toChars());
s = new TupleDeclaration(e->loc, e->id, &(tup->objects));
else
s = new AliasDeclaration(e->loc, e->id, tded);
- s->semantic(sc);
+ dsymbolSemantic(s, sc);
/* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
* More investigation is needed.
*/
{
// arr.length op= e2;
e = ArrayLengthExp::rewriteOpAssign(exp);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
return;
}
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
exp->e1 = exp->e1->optimize(WANTvalue);
exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
exp->type = exp->e1->type;
exp->error("incomplete mixin expression (%s)", se->toChars());
return setError();
}
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
}
void visit(ImportExp *e)
se = new StringExp(e->loc, f.buffer, f.len);
}
}
- result = semantic(se, sc);
+ result = expressionSemantic(se, sc);
}
void visit(AssertExp *exp)
exp->e1 = exp->e1->toBoolean(sc);
if (exp->msg)
{
- exp->msg = semantic(exp->msg, sc);
+ exp->msg = expressionSemantic(exp->msg, sc);
exp->msg = resolveProperties(sc, exp->msg);
exp->msg = exp->msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf());
exp->msg = exp->msg->optimize(WANTvalue);
if (global.params.useAssert == CHECKENABLEoff)
{
Expression *e = new HaltExp(exp->loc);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
exp->var = exp->var->toAlias()->isDeclaration();
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
if (TupleDeclaration *tup = exp->var->isTupleDeclaration())
{
}
Expression *e = new TupleExp(exp->loc, e0, exps);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
/* Later checkRightThis will report correct error for invalid field variable access.
*/
Expression *e = new VarExp(exp->loc, exp->var);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
checkAccess(exp->loc, sc, exp->e1, v);
Expression *e = new VarExp(exp->loc, v);
e = new CommaExp(exp->loc, exp->e1, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
return;
}
- e->e1 = semantic(e->e1, sc);
+ e->e1 = expressionSemantic(e->e1, sc);
e->type = new TypeDelegate(e->func->type);
- e->type = e->type->semantic(e->loc, sc);
+ e->type = typeSemantic(e->type, e->loc, sc);
FuncDeclaration *f = e->func->toAliasFunc();
AggregateDeclaration *ad = f->toParent()->isAggregateDeclaration();
if (f->needThis())
{
// A downcast is required for interfaces, see Bugzilla 3706
e->e1 = new CastExp(e->loc, e->e1, ad->type);
- e->e1 = semantic(e->e1, sc);
+ e->e1 = expressionSemantic(e->e1, sc);
}
result = e;
}
CommaExp *ce = (CommaExp *)exp->e1;
exp->e1 = ce->e2;
ce->e2 = exp;
- result = semantic(ce, sc);
+ result = expressionSemantic(ce, sc);
return;
}
{
DelegateExp *de = (DelegateExp *)exp->e1;
exp->e1 = new DotVarExp(de->loc, de->e1, de->func, de->hasOverloads);
- result = semantic(exp, sc);
+ result = expressionSemantic(exp, sc);
return;
}
}
else
{
- Expression *e1x = semantic(exp->e1, sc);
+ Expression *e1x = expressionSemantic(exp->e1, sc);
if (e1x->op == TOKerror)
{
result = e1x;
}
else
{
- Expression *e1x = semantic(exp->e1, sc);
+ Expression *e1x = expressionSemantic(exp->e1, sc);
if (e1x->op == TOKerror)
{
result =e1x;
if (exp->e1->op == TOKdotid)
{
DotIdExp *die = (DotIdExp *)exp->e1;
- exp->e1 = semantic(die, sc);
+ exp->e1 = expressionSemantic(die, sc);
/* Look for e1 having been rewritten to expr.opDispatch!(string)
* We handle such earlier, so go back.
* Note that in the rewrite, we carefully did not run semantic() on e1
Type *tw = ve->var->type;
Type *tc = ve->var->type->substWildTo(MODconst);
TypeFunction *tf = new TypeFunction(ParameterList(), tc, LINKd, STCsafe | STCpure);
- (tf = (TypeFunction *)tf->semantic(exp->loc, sc))->next = tw; // hack for bug7757
+ (tf = (TypeFunction *)typeSemantic(tf, exp->loc, sc))->next = tw; // hack for bug7757
TypeDelegate *t = new TypeDelegate(tf);
- ve->type = t->semantic(exp->loc, sc);
+ ve->type = typeSemantic(t, exp->loc, sc);
}
VarDeclaration *v = ve->var->isVarDeclaration();
if (v && ve->checkPurity(sc, v))
{
SymOffExp *se = (SymOffExp *)exp->e1;
exp->e1 = new VarExp(se->loc, se->var, true);
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
}
else if (exp->e1->op == TOKdot)
{
else
assert(0);
e = new CallExp(exp->loc, e, exp->arguments);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
// No constructor, look for overload of opCall
*/
Lx:
Expression *e = new StructLiteralExp(exp->loc, sd, exp->arguments, exp->e1->type);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
else if (t1->ty == Tclass)
// Rewrite as e1.call(arguments)
Expression *e = new DotIdExp(exp->loc, exp->e1, Id::call);
e = new CallExp(exp->loc, e, exp->arguments);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
else if (exp->e1->op == TOKtype && t1->isscalar())
exp->error("more than one argument for construction of %s", t1->toChars());
e = new ErrorExp();
}
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
}
BaseClass *b = exp->f->interfaceVirtual;
ClassDeclaration *ad2 = b->sym;
ue->e1 = ue->e1->castTo(sc, ad2->type->addMod(ue->e1->type->mod));
- ue->e1 = semantic(ue->e1, sc);
+ ue->e1 = expressionSemantic(ue->e1, sc);
ue1 = ue->e1;
int vi = exp->f->findVtblIndex((Dsymbols*)&ad2->vtbl, (int)ad2->vtbl.length);
assert(vi >= 0);
else
{
exp->e1 = new DotVarExp(exp->loc, dte->e1, exp->f, false);
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
if (exp->e1->op == TOKerror)
return setError();
ue = (UnaExp *)exp->e1;
if (ad != cd)
{
ue->e1 = ue->e1->castTo(sc, ad->type->addMod(ue->e1->type->mod));
- ue->e1 = semantic(ue->e1, sc);
+ ue->e1 = expressionSemantic(ue->e1, sc);
}
}
}
checkAccess(exp->loc, sc, NULL, exp->f);
exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
t1 = exp->e1->type;
}
else if (exp->e1->op == TOKthis)
//checkAccess(exp->loc, sc, NULL, exp->f); // necessary?
exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
t1 = exp->e1->type;
// BUG: this should really be done by checking the static
}
else if (!t1)
{
- exp->error("function expected before (), not '%s'", exp->e1->toChars());
+ exp->error("function expected before (), not `%s`", exp->e1->toChars());
return setError();
}
else if (t1->ty == Terror)
}
exp->e1 = new VarExp(dve->loc, exp->f, false);
Expression *e = new CommaExp(exp->loc, dve->e1, exp);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
else if (exp->e1->op == TOKvar &&
// Supply an implicit 'this', as in
// this.ident
Expression *ex = new ThisExp(exp->loc);
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
exp->e1 = new DotVarExp(exp->loc, ex, exp->f, false);
goto Lagain;
}
else if (isNeedThisScope(sc, exp->f))
{
- exp->error("need 'this' for '%s' of type '%s'", exp->f->toChars(), exp->f->type->toChars());
+ exp->error("need `this` for `%s` of type `%s`", exp->f->toChars(), exp->f->type->toChars());
return setError();
}
}
bool err = false;
if (!tf->purity && !(sc->flags & SCOPEdebug) && sc->func->setImpure())
{
- exp->error("pure %s '%s' cannot call impure %s '%s'",
+ exp->error("pure %s `%s` cannot call impure %s `%s`",
sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
err = true;
}
if (!tf->isnogc && sc->func->setGC())
{
- exp->error("@nogc %s '%s' cannot call non-@nogc %s '%s'",
+ exp->error("@nogc %s `%s` cannot call non-@nogc %s `%s`",
sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
err = true;
}
if (tf->trust <= TRUSTsystem && sc->func->setUnsafe())
{
- exp->error("@safe %s '%s' cannot call @system %s '%s'",
+ exp->error("@safe %s `%s` cannot call @system %s `%s`",
sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
err = true;
}
// this.ident
Expression *ex = new ThisExp(exp->loc);
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
exp->e1 = new DotVarExp(exp->loc, ex, ve->var);
// Note: we cannot use f directly, because further overload resolution
// through the supplied 'this' may cause different result.
}
else if (isNeedThisScope(sc, exp->f))
{
- exp->error("need 'this' for '%s' of type '%s'", exp->f->toChars(), exp->f->type->toChars());
+ exp->error("need `this` for `%s` of type `%s`", exp->f->toChars(), exp->f->type->toChars());
return setError();
}
}
if (!exp->type)
{
exp->e1 = e1org; // Bugzilla 10922, avoid recursive expression printing
- exp->error("forward reference to inferred return type of function call '%s'", exp->toChars());
+ exp->error("forward reference to inferred return type of function call `%s`", exp->toChars());
return setError();
}
TemplateInstance *ti = dti->ti;
{
//assert(ti->needsTypeInference(sc));
- ti->semantic(sc);
+ dsymbolSemantic(ti, sc);
if (!ti->inst || ti->errors) // if template failed to expand
return setError();
Dsymbol *s = ti->toAlias();
if (f)
{
exp->e1 = new DotVarExp(exp->e1->loc, dti->e1, f);
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
}
}
}
if (ti)
{
//assert(ti->needsTypeInference(sc));
- ti->semantic(sc);
+ dsymbolSemantic(ti, sc);
if (!ti->inst || ti->errors) // if template failed to expand
return setError();
Dsymbol *s = ti->toAlias();
if (f)
{
exp->e1 = new VarExp(exp->e1->loc, f);
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
}
}
}
e = new DelegateExp(exp->loc, dve->e1, f, dve->hasOverloads);
else // It is a function pointer. Convert &v.f() --> (v, &V.f())
e = new CommaExp(exp->loc, dve->e1, new AddrExp(exp->loc, new VarExp(exp->loc, f, dve->hasOverloads)));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
/* Supply a 'null' for a this pointer if no this is available
*/
Expression *e = new DelegateExp(exp->loc, new NullExp(exp->loc, Type::tnull), f, ve->hasOverloads);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
}
Expression *e = new DelegateExp(exp->loc, exp->e1, f, ve->hasOverloads);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
*/
Expression *ethis = new ThisExp(exp->loc);
Expression *e = new DelegateExp(exp->loc, ethis, f, ve->hasOverloads);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
{
if (sc->func->setUnsafe())
{
- exp->error("'this' reference necessary to take address of member %s in @safe function %s",
+ exp->error("`this` reference necessary to take address of member %s in @safe function %s",
f->toChars(), sc->func->toChars());
}
}
// Re-run semantic on the address expressions only
ce->e1->type = NULL;
- ce->e1 = semantic(ce->e1, sc);
+ ce->e1 = expressionSemantic(ce->e1, sc);
ce->e2->type = NULL;
- ce->e2 = semantic(ce->e2, sc);
+ ce->e2 = expressionSemantic(ce->e2, sc);
}
result = exp->optimize(WANTvalue);
break;
default:
- exp->error("can only * a pointer, not a '%s'", exp->e1->type->toChars());
+ exp->error("can only * a pointer, not a `%s`", exp->e1->type->toChars());
/* fall through */
case Terror:
if (fd && f)
{
v = copyToTemp(0, "__tmpea", exp->e1);
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
ea = new DeclarationExp(exp->loc, v);
ea->type = v->type;
}
Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1;
e = new DotVarExp(Loc(), e, fd, false);
eb = new CallExp(exp->loc, e);
- eb = semantic(eb, sc);
+ eb = expressionSemantic(eb, sc);
}
if (f)
Type *tpv = Type::tvoid->pointerTo();
Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1->castTo(sc, tpv);
e = new CallExp(exp->loc, new VarExp(exp->loc, f, false), e);
- ec = semantic(e, sc);
+ ec = expressionSemantic(e, sc);
}
ea = Expression::combine(ea, eb);
ea = Expression::combine(ea, ec);
if (exp->to)
{
- exp->to = exp->to->semantic(exp->loc, sc);
+ exp->to = typeSemantic(exp->to, exp->loc, sc);
if (exp->to == Type::terror)
return setError();
if (!exp->to) // Handle cast(const) and cast(immutable), etc.
{
exp->to = exp->e1->type->castMod(exp->mod);
- exp->to = exp->to->semantic(exp->loc, sc);
+ exp->to = typeSemantic(exp->to, exp->loc, sc);
if (exp->to == Type::terror)
return setError();
}
return;
}
- exp->e1 = semantic(exp->e1, sc);
- exp->type = exp->to->semantic(exp->loc, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
+ exp->type = typeSemantic(exp->to, exp->loc, sc);
if (exp->e1->op == TOKerror || exp->type->ty == Terror)
{
result = exp->e1;
{
if (exp->lwr || exp->upr)
{
- exp->error("cannot slice type '%s'", exp->e1->toChars());
+ exp->error("cannot slice type `%s`", exp->e1->toChars());
return setError();
}
Expression *e = new TypeExp(exp->loc, exp->e1->type->arrayOf());
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
if (!exp->lwr && !exp->upr)
if (exp->lwr)
{
if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->lwr = semantic(exp->lwr, sc);
+ exp->lwr = expressionSemantic(exp->lwr, sc);
exp->lwr = resolveProperties(sc, exp->lwr);
if (t1b->ty == Ttuple) sc = sc->endCTFE();
exp->lwr = exp->lwr->implicitCastTo(sc, Type::tsize_t);
if (exp->upr)
{
if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->upr = semantic(exp->upr, sc);
+ exp->upr = expressionSemantic(exp->upr, sc);
exp->upr = resolveProperties(sc, exp->upr);
if (t1b->ty == Ttuple) sc = sc->endCTFE();
exp->upr = exp->upr->implicitCastTo(sc, Type::tsize_t);
}
e = new TypeExp(exp->e1->loc, new TypeTuple(args));
}
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
if (t1b->ty == Tsarray || t1b->ty == Tarray)
{
Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
- el = semantic(el, sc);
+ el = expressionSemantic(el, sc);
el = el->optimize(WANTvalue);
if (el->op == TOKint64)
{
}
Expression *le = e->lwr;
- le = semantic(le, sc);
+ le = expressionSemantic(le, sc);
le = resolveProperties(sc, le);
Expression *ue = e->upr;
- ue = semantic(ue, sc);
+ ue = expressionSemantic(ue, sc);
ue = resolveProperties(sc, ue);
if (le->op == TOKerror)
void visit(DotExp *exp)
{
- exp->e1 = semantic(exp->e1, sc);
- exp->e2 = semantic(exp->e2, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
+ exp->e2 = expressionSemantic(exp->e2, sc);
if (exp->e1->op == TOKtype)
{
{
TemplateDeclaration *td = ((TemplateExp *)exp->e2)->td;
Expression *e = new DotTemplateExp(exp->loc, exp->e1, td);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
if (!exp->type)
// operator overloading should be handled in ArrayExp already.
if (!exp->e1->type)
- exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = expressionSemantic(exp->e1, sc);
assert(exp->e1->type); // semantic() should already be run on it
if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
{
- exp->e2 = semantic(exp->e2, sc);
+ exp->e2 = expressionSemantic(exp->e2, sc);
exp->e2 = resolveProperties(sc, exp->e2);
Type *nt;
if (exp->e2->op == TOKtype)
else
nt = new TypeSArray(exp->e1->type, exp->e2);
Expression *e = new TypeExp(exp->loc, nt);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
if (exp->e1->op == TOKerror)
sc = sc->push(sym);
}
if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->e2 = semantic(exp->e2, sc);
+ exp->e2 = expressionSemantic(exp->e2, sc);
exp->e2 = resolveProperties(sc, exp->e2);
if (t1b->ty == Ttuple) sc = sc->endCTFE();
if (exp->e2->op == TOKtuple)
;
else if (sc->func && sc->func->setUnsafe())
{
- exp->error("safe function '%s' cannot index pointer '%s'",
+ exp->error("safe function `%s` cannot index pointer `%s`",
sc->func->toPrettyChars(), exp->e1->toChars());
return setError();
}
if (t1b->ty == Tsarray || t1b->ty == Tarray)
{
Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
- el = semantic(el, sc);
+ el = expressionSemantic(el, sc);
el = el->optimize(WANTvalue);
if (el->op == TOKint64)
{
if (exp->e1->op == TOKslice)
{
const char *s = exp->op == TOKplusplus ? "increment" : "decrement";
- exp->error("cannot post-%s array slice '%s', use pre-%s instead", s, exp->e1->toChars(), s);
+ exp->error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp->e1->toChars(), s);
return setError();
}
ea = new CommaExp(exp->loc, de, ea);
e = new CommaExp(exp->loc, ea, eb);
e = new CommaExp(exp->loc, e, ec);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
e = new AddAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
else
e = new MinAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
}
void visit(AssignExp *exp)
Expression *e0;
exp->e2 = Expression::extractLast(exp->e2, &e0);
Expression *e = Expression::combine(e0, exp);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
Expression *res;
ArrayExp *ae = (ArrayExp *)exp->e1;
- ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = expressionSemantic(ae->e1, sc);
ae->e1 = resolveProperties(sc, ae->e1);
Expression *ae1old = ae->e1;
return;
}
- res = semantic(exp->e2, sc);
+ res = expressionSemantic(exp->e2, sc);
if (res->op == TOKerror)
{
result = res;
if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
res = trySemantic(res, sc);
else
- res = semantic(res, sc);
+ res = expressionSemantic(res, sc);
if (res)
{
res = Expression::combine(e0, res);
return;
}
- res = semantic(exp->e2, sc);
+ res = expressionSemantic(exp->e2, sc);
if (res->op == TOKerror)
{
result = res;
}
res = new DotIdExp(exp->loc, ae->e1, Id::sliceass);
res = new CallExp(exp->loc, res, a);
- res = semantic(res, sc);
+ res = expressionSemantic(res, sc);
res = Expression::combine(e0, res);
result = res;
return;
if (e1x->op == TOKslice)
((SliceExp *)e1x)->arrayop = true;
- e1x = semantic(e1x, sc);
+ e1x = expressionSemantic(e1x, sc);
}
/* We have f = value.
{
Expression *e2x = inferType(exp->e2, t1->baseElemOf());
- e2x = semantic(e2x, sc);
+ e2x = expressionSemantic(e2x, sc);
e2x = resolveProperties(sc, e2x);
if (e2x->op == TOKtype)
}
e = new TupleExp(exp->loc, Expression::combine(tup1->e0, tup2->e0), exps);
}
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
}
}
e2x = new TupleExp(e2x->loc, e0, iexps);
- e2x = semantic(e2x, sc);
+ e2x = expressionSemantic(e2x, sc);
if (e2x->op == TOKerror)
{
result = e2x;
Expression *e = Expression::combine(ae, cx);
e = Expression::combine(e0, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
Expression *ea1 = new ConstructExp(econd->e1->loc, e1x, econd->e1);
Expression *ea2 = new ConstructExp(econd->e1->loc, e1x, econd->e2);
Expression *e = new CondExp(exp->loc, econd->econd, ea1, ea2);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
e = new BlitExp(exp->loc, e, e2x);
e = new DotVarExp(exp->loc, e, sd->postblit, false);
e = new CallExp(exp->loc, e);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
return;
}
else
e = new DotIdExp(exp->loc, e1x, Id::ctor);
e = new CallExp(exp->loc, e, e2x);
e = new CommaExp(exp->loc, einit, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
e2x = typeDotIdExp(e2x->loc, e1x->type, Id::call);
e2x = new CallExp(exp->loc, e2x, exp->e2);
- e2x = semantic(e2x, sc);
+ e2x = expressionSemantic(e2x, sc);
e2x = resolveProperties(sc, e2x);
if (e2x->op == TOKerror)
{
* (e1 op e2.aliasthis)
*/
exp->e2 = new DotIdExp(exp->e2->loc, exp->e2, ad2->aliasthis->ident);
- result = semantic(exp, sc);
+ result = expressionSemantic(exp, sc);
return;
}
}
AssignExp *ae = (AssignExp *)exp->copy();
ae->e1 = new IndexExp(exp->loc, ea, ek);
- ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = expressionSemantic(ae->e1, sc);
ae->e1 = ae->e1->optimize(WANTvalue);
ae->e2 = ev;
Expression *e = ae->op_overload(sc);
{
Expression *ex;
ex = new IndexExp(exp->loc, ea, ek);
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
ex = ex->optimize(WANTvalue);
ex = ex->modifiableLvalue(sc, ex); // allocate new slot
ey = new ConstructExp(exp->loc, ex, ey);
- ey = semantic(ey, sc);
+ ey = expressionSemantic(ey, sc);
if (ey->op == TOKerror)
{
result = ey;
e = new CondExp(exp->loc, new InExp(exp->loc, ek, ea), ex, ey);
}
e = Expression::combine(e0, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
// e.g. e1[] = a[] + b[];
SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
sle->arrayop = true;
- e1x = semantic(sle, sc);
+ e1x = expressionSemantic(sle, sc);
}
else
{
}
SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
sle->arrayop = true;
- e1x = semantic(sle, sc);
+ e1x = expressionSemantic(sle, sc);
}
if (e1x->op == TOKerror)
{
e = new CommaExp(exp->loc, de, e);
}
e = Expression::combine(e0, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
exp->e1->type = exp->type;
exp->e2->type = exp->type;
e = new NegExp(exp->loc, exp);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
// x/iv = i(-x/v)
exp->e2->type = t1;
e = new NegExp(exp->loc, exp);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
if (s->mod)
{
s->mod->importAll(NULL);
- s->mod->semantic(NULL);
+ dsymbolSemantic(s->mod, NULL);
}
impStdMath = s;
}
e = exp->optimize(WANTvalue);
if (e->op != TOKpow)
{
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
if (intpow == 3)
me = new MulExp(exp->loc, me, ve);
e = new CommaExp(exp->loc, de, me);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
return;
}
// Replace e1 ^^ e2 with .std.math.pow(e1, e2)
e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_pow), exp->e1, exp->e2);
}
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
result = e;
}
setNoderefOperands(exp);
- Expression *e1x = semantic(exp->e1, sc);
+ Expression *e1x = expressionSemantic(exp->e1, sc);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
if (e1x->op == TOKtype)
}
}
- Expression *e2x = semantic(exp->e2, sc);
+ Expression *e2x = expressionSemantic(exp->e2, sc);
sc->mergeCallSuper(exp->loc, cs1);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
if (e->op == TOKcall)
{
e = new CmpExp(exp->op, exp->loc, e, new IntegerExp(exp->loc, 0, Type::tint32));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
result = e;
return;
(t1->ty == Tarray || t1->ty == Tsarray ||
t2->ty == Tarray || t2->ty == Tsarray))
{
- exp->error("'%s' is not defined for array comparisons", Token::toChars(exp->op));
+ exp->error("`%s` is not defined for array comparisons", Token::toChars(exp->op));
return setError();
}
if (altop != TOKreserved)
if (altop == TOKerror)
{
const char *s = exp->op == TOKunord ? "false" : "true";
- exp->error("floating point operator '%s' always returns %s for non-floating comparisons",
+ exp->error("floating point operator `%s` always returns %s for non-floating comparisons",
Token::toChars(exp->op), s);
}
else
{
- exp->error("use '%s' for non-floating comparisons rather than floating point operator '%s'",
+ exp->error("use `%s` for non-floating comparisons rather than floating point operator `%s`",
Token::toChars(altop), Token::toChars(exp->op));
}
}
else
{
- exp->error("use std.math.isNaN to deal with NaN operands rather than floating point operator '%s'",
+ exp->error("use std.math.isNaN to deal with NaN operands rather than floating point operator `%s`",
Token::toChars(exp->op));
}
return setError();
if (exp->econd->op == TOKdotid)
((DotIdExp *)exp->econd)->noderef = true;
- Expression *ec = semantic(exp->econd, sc);
+ Expression *ec = expressionSemantic(exp->econd, sc);
ec = resolveProperties(sc, ec);
ec = ec->toBoolean(sc);
unsigned cs0 = sc->callSuper;
unsigned *fi0 = sc->saveFieldInit();
- Expression *e1x = semantic(exp->e1, sc);
+ Expression *e1x = expressionSemantic(exp->e1, sc);
e1x = resolveProperties(sc, e1x);
unsigned cs1 = sc->callSuper;
unsigned *fi1 = sc->fieldinit;
sc->callSuper = cs0;
sc->fieldinit = fi0;
- Expression *e2x = semantic(exp->e2, sc);
+ Expression *e2x = expressionSemantic(exp->e2, sc);
e2x = resolveProperties(sc, e2x);
sc->mergeCallSuper(exp->loc, cs1);
{
//printf("+trySemantic(%s)\n", toChars());
unsigned errors = global.startGagging();
- Expression *e = semantic(exp, sc);
+ Expression *e = expressionSemantic(exp, sc);
if (global.endGagging(errors))
{
e = NULL;
*/
Expression *unaSemantic(UnaExp *e, Scope *sc)
{
- Expression *e1x = semantic(e->e1, sc);
+ Expression *e1x = expressionSemantic(e->e1, sc);
if (e1x->op == TOKerror)
return e1x;
e->e1 = e1x;
*/
Expression *binSemantic(BinExp *e, Scope *sc)
{
- Expression *e1x = semantic(e->e1, sc);
- Expression *e2x = semantic(e->e2, sc);
+ Expression *e1x = expressionSemantic(e->e1, sc);
+ Expression *e2x = expressionSemantic(e->e2, sc);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
if (e1x->op == TOKtype)
}
// entrypoint for semantic ExpressionSemanticVisitor
-Expression *semantic(Expression *e, Scope *sc)
+Expression *expressionSemantic(Expression *e, Scope *sc)
{
ExpressionSemanticVisitor v = ExpressionSemanticVisitor(sc);
e->accept(&v);
mangleToBuffer(ds, &buf);
const char *s = buf.extractChars();
Expression *e = new StringExp(exp->loc, const_cast<char*>(s), strlen(s));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
default:
for (size_t i = 0; i < exps->length; i++)
{
Expression *e = (*te->exps)[i];
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = new DotIdExp(e->loc, e, Id::offsetof);
(*exps)[i] = e;
}
// Don't evaluate te->e0 in runtime
Expression *e = new TupleExp(exp->loc, NULL, exps);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (exp->e1->op == TOKtuple && exp->ident == Id::length)
// Bugzilla 14416: Template has no built-in properties except for 'stringof'.
if ((exp->e1->op == TOKdottd || exp->e1->op == TOKtemplate) && exp->ident != Id::stringof)
{
- exp->error("template %s does not have property '%s'", exp->e1->toChars(), exp->ident->toChars());
+ exp->error("template %s does not have property `%s`", exp->e1->toChars(), exp->ident->toChars());
return new ErrorExp();
}
if (!exp->e1->type)
{
- exp->error("expression %s does not have property '%s'", exp->e1->toChars(), exp->ident->toChars());
+ exp->error("expression %s does not have property `%s`", exp->e1->toChars(), exp->ident->toChars());
return new ErrorExp();
}
(!v->type->deco && v->inuse))
{
if (v->inuse)
- exp->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ exp->error("circular reference to %s `%s`", v->kind(), v->toPrettyChars());
else
- exp->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ exp->error("forward reference to %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
if (v->type->ty == Terror)
*/
if (v->inuse)
{
- ::error(exp->loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ ::error(exp->loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
e = v->expandInitializer(exp->loc);
v->inuse++;
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
v->inuse--;
return e;
}
if (!eleft)
eleft = new ThisExp(exp->loc);
e = new DotVarExp(exp->loc, eleft, v);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
else
{
}
}
e = e->deref();
- return semantic(e, sc);
+ return expressionSemantic(e, sc);
}
FuncDeclaration *f = s->isFuncDeclaration();
if (!eleft)
eleft = new ThisExp(exp->loc);
e = new DotVarExp(exp->loc, eleft, f, true);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
else
{
e = new DotTemplateExp(exp->loc, eleft, td);
else
e = new TemplateExp(exp->loc, td);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (OverDeclaration *od = s->isOverDeclaration())
if (Type *t = s->getType())
{
- return semantic(new TypeExp(exp->loc, t), sc);
+ return expressionSemantic(new TypeExp(exp->loc, t), sc);
}
TupleDeclaration *tup = s->isTupleDeclaration();
if (eleft)
{
e = new DotVarExp(exp->loc, eleft, tup);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
e = new TupleExp(exp->loc, tup);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
{
//printf("it's a ScopeDsymbol %s\n", exp->ident->toChars());
e = new ScopeExp(exp->loc, sds);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (eleft)
e = new DotExp(exp->loc, eleft, e);
return e;
if (imp)
{
ie = new ScopeExp(exp->loc, imp->pkg);
- return semantic(ie, sc);
+ return expressionSemantic(ie, sc);
}
// BUG: handle other cases like in IdentifierExp::semantic()
{
const char *p = ie->toChars();
e = new StringExp(exp->loc, const_cast<char *>(p), strlen(p));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (ie->sds->isPackage() ||
exp->error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`",
exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->toPrettyChars());
else
- exp->error("undefined identifier '%s' in %s '%s', did you mean %s '%s'?",
+ exp->error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?",
exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->kind(), s->toChars());
}
else
- exp->error("undefined identifier '%s' in %s '%s'",
+ exp->error("undefined identifier `%s` in %s `%s`",
exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars());
return new ErrorExp();
}
if (flag && t1bn->ty == Tvoid)
return NULL;
e = new PtrExp(exp->loc, exp->e1);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e->type->dotExp(sc, e, exp->ident, flag | (exp->noderef ? 2 : 0));
}
else
flag = 0;
e = exp->e1->type->dotExp(sc, exp->e1, exp->ident, flag | (exp->noderef ? 2 : 0));
if (e)
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
}
if (td)
{
e = new DotTemplateExp(dve->loc, dve->e1, td);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
}
else if (dve->var->isOverDeclaration())
goto Lerr;
if (exp->ti->needsTypeInference(sc))
return exp;
- exp->ti->semantic(sc);
+ dsymbolSemantic(exp->ti, sc);
if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
return new ErrorExp();
Dsymbol *s = exp->ti->toAlias();
if (v)
{
if (v->type && !v->type->deco)
- v->type = v->type->semantic(v->loc, sc);
+ v->type = typeSemantic(v->type, v->loc, sc);
e = new DotVarExp(exp->loc, exp->e1, v);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
e = new ScopeExp(exp->loc, exp->ti);
e = new DotExp(exp->loc, exp->e1, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
}
if (td)
{
e = new TemplateExp(ve->loc, td);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
}
else if (OverDeclaration *od = ve->var->isOverDeclaration())
{
exp->ti->tempdecl = od;
e = new ScopeExp(exp->loc, exp->ti);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
}
return new ErrorExp();
if (exp->ti->needsTypeInference(sc))
return exp;
- exp->ti->semantic(sc);
+ dsymbolSemantic(exp->ti, sc);
if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
return new ErrorExp();
Dsymbol *s = exp->ti->toAlias();
if (v && (v->isFuncDeclaration() || v->isVarDeclaration()))
{
e = new DotVarExp(exp->loc, exp->e1, v);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
e = new ScopeExp(exp->loc, exp->ti);
e = new DotExp(exp->loc, exp->e1, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
else if (e->op == TOKtemplate)
{
exp->ti->tempdecl = ((TemplateExp *)e)->td;
e = new ScopeExp(exp->loc, exp->ti);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
else if (e->op == TOKdot)
}
if (exp->ti->needsTypeInference(sc))
return exp;
- exp->ti->semantic(sc);
+ dsymbolSemantic(exp->ti, sc);
if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
return new ErrorExp();
Dsymbol *s = exp->ti->toAlias();
if (v)
{
if (v->type && !v->type->deco)
- v->type = v->type->semantic(v->loc, sc);
+ v->type = typeSemantic(v->type, v->loc, sc);
e = new DotVarExp(exp->loc, exp->e1, v);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
e = new ScopeExp(exp->loc, exp->ti);
e = new DotExp(exp->loc, exp->e1, e);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
}
OverExp *oe = (OverExp *)e;
exp->ti->tempdecl = oe->vars;
e = new ScopeExp(exp->loc, exp->ti);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
Lerr:
/* 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.
#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.
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);
return true;
}
-// Do the semantic analysis on the external interface to the function.
-
-void FuncDeclaration::semantic(Scope *sc)
+/****************************************************
+ * Determine whether an 'out' contract is declared inside
+ * the given function or any of its overrides.
+ * Params:
+ * fd = the function to search
+ * Returns:
+ * true found an 'out' contract
+ * false didn't find one
+ */
+bool FuncDeclaration::needsFensure(FuncDeclaration *fd)
{
- 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);
- }
+ if (fd->fensures)
+ return true;
- 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
+ for (size_t i = 0; i < fd->foverrides.length; i++)
{
- // 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;
+ FuncDeclaration *fdv = fd->foverrides[i];
- 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 (fdv->fensure)
+ return true;
- 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 (needsFensure(fdv))
+ return true;
}
+ return false;
+}
- 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);
- }
+/****************************************************
+ * Check whether result variable can be built.
+ * Returns:
+ * `true` if the function has a return type that
+ * is different from `void`.
+ */
+static bool canBuildResultVar(FuncDeclaration *fd)
+{
+ TypeFunction *f = (TypeFunction *)fd->type;
+ return f && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid;
+}
- 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.
- * Params:
- * fd = the function to search
- * Returns:
- * true found an 'out' contract
- * false didn't find one
- */
-static bool needsFensure(FuncDeclaration *fd)
-{
- if (fd->fensures)
- return true;
-
- for (size_t i = 0; i < fd->foverrides.length; i++)
- {
- FuncDeclaration *fdv = fd->foverrides[i];
-
- if (fdv->fensure)
- return true;
-
- if (needsFensure(fdv))
- return true;
- }
- return false;
-}
-
-/****************************************************
- * Check whether result variable can be built.
- * Returns:
- * `true` if the function has a return type that
- * is different from `void`.
- */
-static bool canBuildResultVar(FuncDeclaration *fd)
-{
- TypeFunction *f = (TypeFunction *)fd->type;
- return f && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid;
-}
-
-/****************************************************
- * Rewrite contracts as statements.
- * Params:
- * fdx = the function to rewrite contracts for
- */
-static void buildEnsureRequire(FuncDeclaration *fdx)
-{
- if (fdx->frequires)
+/****************************************************
+ * Rewrite contracts as statements.
+ */
+void FuncDeclaration::buildEnsureRequire()
+{
+ if (frequires)
{
/* in { statements1... }
* in { statements2... }
* ...
* becomes:
- * in { { statements1... } { statements2... } ... }
- */
- assert(fdx->frequires->length);
- Loc loc = (*fdx->frequires)[0]->loc;
- Statements *s = new Statements;
- for (size_t i = 0; i < fdx->frequires->length; i++)
- {
- Statement *r = (*fdx->frequires)[i];
- s->push(new ScopeStatement(r->loc, r, r->loc));
- }
- fdx->frequire = new CompoundStatement(loc, s);
- }
-
- if (fdx->fensures)
- {
- /* out(id1) { statements1... }
- * out(id2) { statements2... }
- * ...
- * becomes:
- * out(__result) { { ref id1 = __result; { statements1... } }
- * { ref id2 = __result; { statements2... } } ... }
- */
- assert(fdx->fensures->length);
- Loc loc = (*fdx->fensures)[0].ensure->loc;
- Statements *s = new Statements;
- for (size_t i = 0; i < fdx->fensures->length; i++)
- {
- Ensure r = (*fdx->fensures)[i];
- if (r.id && canBuildResultVar(fdx))
- {
- Loc rloc = r.ensure->loc;
- IdentifierExp *resultId = new IdentifierExp(rloc, Id::result);
- ExpInitializer *init = new ExpInitializer(rloc, resultId);
- StorageClass stc = STCref | STCtemp | STCresult;
- VarDeclaration *decl = new VarDeclaration(rloc, NULL, r.id, init);
- decl->storage_class = stc;
- ExpStatement *sdecl = new ExpStatement(rloc, decl);
- s->push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
- }
- else
- {
- s->push(r.ensure);
- }
- }
- fdx->fensure = new CompoundStatement(loc, s);
- }
-
- if (!fdx->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;
-
- if (fdx->frequire)
- {
- /* in { ... }
- * becomes:
- * void __require() { ... }
- * __require();
- */
- Loc loc = fdx->frequire->loc;
- TypeFunction *tf = new TypeFunction(ParameterList(), Type::tvoid, LINKd);
- tf->isnothrow = f->isnothrow;
- tf->isnogc = f->isnogc;
- tf->purity = f->purity;
- tf->trust = f->trust;
- FuncDeclaration *fd = new FuncDeclaration(loc, loc,
- Id::require, STCundefined, tf);
- fd->fbody = fdx->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;
- }
-
- if (fdx->fensure)
- {
- /* out (result) { ... }
- * becomes:
- * void __ensure(ref tret result) { ... }
- * __ensure(result);
- */
- Loc loc = fdx->fensure->loc;
- Parameters *fparams = new Parameters();
- Parameter *p = NULL;
- if (canBuildResultVar(fdx))
- {
- p = new Parameter(STCref | STCconst, f->nextOf(), Id::result, NULL, NULL);
- fparams->push(p);
- }
- TypeFunction *tf = new TypeFunction(ParameterList(fparams), Type::tvoid, LINKd);
- tf->isnothrow = f->isnothrow;
- tf->isnogc = f->isnogc;
- tf->purity = f->purity;
- tf->trust = f->trust;
- FuncDeclaration *fd = new FuncDeclaration(loc, loc,
- Id::ensure, STCundefined, tf);
- fd->fbody = fdx->fensure;
- Statement *s1 = new ExpStatement(loc, fd);
- Expression *eresult = NULL;
- if (canBuildResultVar(fdx))
- 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;
- }
-}
-
-/* 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)
+ * in { { statements1... } { statements2... } ... }
+ */
+ assert(frequires->length);
+ Loc loc = (*frequires)[0]->loc;
+ Statements *s = new Statements;
+ for (size_t i = 0; i < frequires->length; i++)
{
- if (type == f)
- f = (TypeFunction *)f->copy();
- f->isreturn = true;
+ Statement *r = (*frequires)[i];
+ s->push(new ScopeStatement(r->loc, r, r->loc));
}
+ frequire = new CompoundStatement(loc, s);
}
- flags &= ~FUNCFLAGinferScope;
-
- // Infer STCscope
- if (parameters)
+ if (fensures)
{
- size_t nfparams = f->parameterList.length();
- assert(nfparams == parameters->length);
- for (size_t u = 0; u < parameters->length; u++)
+ /* out(id1) { statements1... }
+ * out(id2) { statements2... }
+ * ...
+ * becomes:
+ * out(__result) { { ref id1 = __result; { statements1... } }
+ * { ref id2 = __result; { statements2... } } ... }
+ */
+ assert(fensures->length);
+ Loc loc = (*fensures)[0].ensure->loc;
+ Statements *s = new Statements;
+ for (size_t i = 0; i < fensures->length; i++)
{
- VarDeclaration *v = (*parameters)[u];
- if (v->storage_class & STCmaybescope)
+ Ensure r = (*fensures)[i];
+ if (r.id && canBuildResultVar(this))
+ {
+ Loc rloc = r.ensure->loc;
+ IdentifierExp *resultId = new IdentifierExp(rloc, Id::result);
+ ExpInitializer *init = new ExpInitializer(rloc, resultId);
+ StorageClass stc = STCref | STCtemp | STCresult;
+ VarDeclaration *decl = new VarDeclaration(rloc, NULL, r.id, init);
+ decl->storage_class = stc;
+ ExpStatement *sdecl = new ExpStatement(rloc, decl);
+ s->push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
+ }
+ else
{
- //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));
+ s->push(r.ensure);
}
}
+ fensure = new CompoundStatement(loc, s);
}
- if (vthis && vthis->storage_class & STCmaybescope)
- {
- vthis->storage_class &= ~STCmaybescope;
- vthis->storage_class |= STCscope | STCscopeinferred;
- f->isscope = true;
- f->isscopeinferred = true;
- }
+ if (!isVirtual())
+ return;
- // reset deco to apply inference result to mangled name
- if (f != type)
- f->deco = NULL;
+ /* Rewrite contracts as nested functions, then call them. Doing it as nested
+ * functions means that overriding functions can call them.
+ */
+ TypeFunction *f = (TypeFunction *)type;
- // Do semantic type AFTER pure/nothrow inference.
- if (!f->deco && ident != Id::xopEquals && ident != Id::xopCmp)
+ if (frequire)
{
- 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();
+ /* in { ... }
+ * becomes:
+ * void __require() { ... }
+ * __require();
+ */
+ Loc loc = frequire->loc;
+ TypeFunction *tf = new TypeFunction(ParameterList(), Type::tvoid, LINKd);
+ tf->isnothrow = f->isnothrow;
+ tf->isnogc = f->isnogc;
+ tf->purity = f->purity;
+ tf->trust = f->trust;
+ FuncDeclaration *fd = new FuncDeclaration(loc, loc,
+ Id::require, STCundefined, tf);
+ fd->fbody = frequire;
+ Statement *s1 = new ExpStatement(loc, fd);
+ Expression *e = new CallExp(loc, new VarExp(loc, fd, false), (Expressions *)NULL);
+ Statement *s2 = new ExpStatement(loc, e);
+ frequire = new CompoundStatement(loc, s1, s2);
+ fdrequire = fd;
}
- /* If 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);
+ if (fensure)
+ {
+ /* out (result) { ... }
+ * becomes:
+ * void __ensure(ref tret result) { ... }
+ * __ensure(result);
+ */
+ Loc loc = fensure->loc;
+ Parameters *fparams = new Parameters();
+ Parameter *p = NULL;
+ if (canBuildResultVar(this))
+ {
+ p = new Parameter(STCref | STCconst, f->nextOf(), Id::result, NULL, NULL);
+ fparams->push(p);
+ }
+ TypeFunction *tf = new TypeFunction(ParameterList(fparams), Type::tvoid, LINKd);
+ tf->isnothrow = f->isnothrow;
+ tf->isnogc = f->isnogc;
+ tf->purity = f->purity;
+ tf->trust = f->trust;
+ FuncDeclaration *fd = new FuncDeclaration(loc, loc,
+ Id::ensure, STCundefined, tf);
+ fd->fbody = fensure;
+ Statement *s1 = new ExpStatement(loc, fd);
+ Expression *eresult = NULL;
+ if (canBuildResultVar(this))
+ eresult = new IdentifierExp(loc, Id::result);
+ Expression *e = new CallExp(loc, new VarExp(loc, fd, false), eresult);
+ Statement *s2 = new ExpStatement(loc, e);
+ fensure = new CompoundStatement(loc, s1, s2);
+ fdensure = fd;
+ }
}
/****************************************************
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);
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,
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;
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;
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;
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());
assert(fdv->_scope);
Scope *sc = fdv->_scope->push();
sc->stc &= ~STCoverride;
- fdv->semantic3(sc);
+ semantic3(fdv, sc);
sc->pop();
}
assert(fdv->_scope);
Scope *sc = fdv->_scope->push();
sc->stc &= ~STCoverride;
- fdv->semantic3(sc);
+ semantic3(fdv, sc);
sc->pop();
}
}
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
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",
{
//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",
!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.
*/
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";
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
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
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;
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;
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;
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;
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";
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";
/* 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.
/* 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 Dave Fladebo
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
/* 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 Dave Fladebo
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
/* Compiler implementation of the D programming language
- * Copyright (C) 2018-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2018-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.
/* Compiler implementation of the D programming language
- * Copyright (C) 2018-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2018-2021 by The D Language Foundation, All Rights Reserved
* written by Iain Buclaw
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
*/
#include "scope.h"
+#include "expression.h"
#include "declaration.h"
#include "errors.h"
#include "parse.h"
#include "statement.h"
-Expression *semantic(Expression *e, Scope *sc);
-Statement *semantic(Statement *s, Scope *sc);
-
/***********************************
* Parse list of extended asm input or output operands.
* Grammar:
s->stc = sc->stc;
// Fold the instruction template string.
- s->insn = semantic(s->insn, sc);
+ s->insn = expressionSemantic(s->insn, sc);
s->insn = s->insn->ctfeInterpret();
if (s->insn->op != TOKstring || ((StringExp *) s->insn)->sz != 1)
for (size_t i = 0; i < s->args->length; i++)
{
Expression *e = (*s->args)[i];
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
// Check argument is a valid lvalue/rvalue.
if (i < s->outputargs)
e = e->modifiableLvalue(sc, NULL);
(*s->args)[i] = e;
e = (*s->constraints)[i];
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
(*s->constraints)[i] = e;
}
for (size_t i = 0; i < s->clobbers->length; i++)
{
Expression *e = (*s->clobbers)[i];
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
(*s->clobbers)[i] = e;
}
if (!s->gotos)
s->gotos = new GotoStatements();
s->gotos->push(gs);
- semantic(gs, sc);
+ statementSemantic(gs, sc);
}
}
/* 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.
/* 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.
/* 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.
/* 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.
/* Compiler implementation of the D programming language
- * Copyright (C) 2010-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2010-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.
/* 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.
Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
void load(Scope *sc);
void importAll(Scope *sc);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
Dsymbol *toAlias();
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope* sc);
/* 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.
#include "id.h"
#include "tokens.h"
-Expression *semantic(Expression *e, Scope *sc);
-Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
-
/********************************** Initializer *******************************/
Initializer::Initializer(Loc loc)
/* 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.
struct Scope;
class Type;
class AggregateDeclaration;
+class Initializer;
class ErrorInitializer;
class VoidInitializer;
class StructInitializer;
enum NeedInterpret { INITnointerpret, INITinterpret };
+Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
class Initializer : public ASTNode
{
public:
/* 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.
#include "id.h"
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
-Expression *semantic(Expression *e, Scope *sc);
Initializer *inferType(Initializer *init, Scope *sc);
-Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
bool hasNonConstPointers(Expression *e);
class InitializerSemanticVisitor : public Visitor
{
s = sd->search_correct(id);
if (s)
- error(i->loc, "'%s' is not a member of '%s', did you mean %s '%s'?",
+ error(i->loc, "`%s` is not a member of `%s`, did you mean %s `%s`?",
id->toChars(), sd->toChars(), s->kind(), s->toChars());
else
- error(i->loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
+ error(i->loc, "`%s` is not a member of `%s`", id->toChars(), sd->toChars());
result = new ErrorInitializer();
return;
}
VarDeclaration *vd = sd->fields[fieldi];
if ((*elements)[fieldi])
{
- error(i->loc, "duplicate initializer for field '%s'", vd->toChars());
+ error(i->loc, "duplicate initializer for field `%s`", vd->toChars());
errors = true;
continue;
}
assert(sc);
Initializer *iz = i->value[j];
- iz = ::semantic(iz, sc, vd->type->addMod(t->mod), needInterpret);
+ iz = initializerSemantic(iz, sc, vd->type->addMod(t->mod), needInterpret);
Expression *ex = initializerToExpression(iz);
if (ex->op == TOKerror)
{
sle->type = t;
ExpInitializer *ie = new ExpInitializer(i->loc, sle);
- result = ::semantic(ie, sc, t, needInterpret);
+ result = initializerSemantic(ie, sc, t, needInterpret);
return;
}
else if ((t->ty == Tdelegate || (t->ty == Tpointer && t->nextOf()->ty == Tfunction)) && i->value.length == 0)
fd->endloc = i->loc;
Expression *e = new FuncExp(i->loc, fd);
ExpInitializer *ie = new ExpInitializer(i->loc, e);
- result = ::semantic(ie, sc, t, needInterpret);
+ result = initializerSemantic(ie, sc, t, needInterpret);
return;
}
goto Lerr;
}
ExpInitializer *ei = new ExpInitializer(e->loc, e);
- result = ::semantic(ei, sc, t, needInterpret);
+ result = initializerSemantic(ei, sc, t, needInterpret);
return;
}
case Tpointer:
if (idx)
{
sc = sc->startCTFE();
- idx = ::semantic(idx, sc);
+ idx = expressionSemantic(idx, sc);
sc = sc->endCTFE();
idx = idx->ctfeInterpret();
i->index[j] = idx;
ExpInitializer *ei = val->isExpInitializer();
if (ei && !idx)
ei->expandTuples = true;
- val = ::semantic(val, sc, t->nextOf(), needInterpret);
+ val = initializerSemantic(val, sc, t->nextOf(), needInterpret);
if (val->isErrorInitializer())
errors = true;
{
//printf("ExpInitializer::semantic(%s), type = %s\n", i->exp->toChars(), t->toChars());
if (needInterpret) sc = sc->startCTFE();
- i->exp = ::semantic(i->exp, sc);
+ i->exp = expressionSemantic(i->exp, sc);
i->exp = resolveProperties(sc, i->exp);
if (needInterpret) sc = sc->endCTFE();
if (i->exp->op == TOKerror)
}
if (i->exp->op == TOKtype)
{
- i->exp->error("initializer must be an expression, not '%s'", i->exp->toChars());
+ i->exp->error("initializer must be an expression, not `%s`", i->exp->toChars());
result = new ErrorInitializer();
return;
}
// Make sure all pointers are constants
if (needInterpret && hasNonConstPointers(i->exp))
{
- i->exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", i->exp->toChars());
+ i->exp->error("cannot use non-constant CTFE pointer in an initializer `%s`", i->exp->toChars());
result = new ErrorInitializer();
return;
}
e = new StructLiteralExp(i->loc, sd, NULL);
e = new DotIdExp(i->loc, e, Id::ctor);
e = new CallExp(i->loc, e, i->exp);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
if (needInterpret)
i->exp = e->ctfeInterpret();
else
};
// Performs semantic analisys on Initializer AST nodes
-Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret)
+Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret)
{
InitializerSemanticVisitor v = InitializerSemanticVisitor(sc, t, needInterpret);
init->accept(&v);
void visit(ExpInitializer *init)
{
//printf("ExpInitializer::inferType() %s\n", init->toChars());
- init->exp = ::semantic(init->exp, sc);
+ init->exp = expressionSemantic(init->exp, sc);
init->exp = resolveProperties(sc, init->exp);
if (init->exp->op == TOKscope)
size_t d = (size_t)tsa->dim->toInteger();
Expressions *elements = new Expressions();
elements->setDim(d);
- for (size_t i = 0; i < d; i++)
- (*elements)[i] = e;
+ for (size_t j = 0; j < d; j++)
+ (*elements)[j] = e;
ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, itype, elements);
result = ae;
return;
/* 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 KennyTM
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
/* 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 KennyTM
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
/* 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.
/* 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.
/* 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.
++p;
if (base < 10 && !err)
{
- error("radix %d digit expected, not '%c'", base, c);
+ error("radix %d digit expected, not `%c`", base, c);
err = true;
}
d = c - '0';
goto Lreal;
if (!err)
{
- error("radix %d digit expected, not '%c'", base, c);
+ error("radix %d digit expected, not `%c`", base, c);
err = true;
}
}
if (isOutOfRange && !isLong)
{
const char *suffix = (result == TOKfloat32v || result == TOKimaginary32v) ? "f" : "";
- error(scanloc, "number '%s%s' is not representable", (char *)stringbuffer.slice().ptr, suffix);
+ error(scanloc, "number `%s%s` is not representable", (char *)stringbuffer.slice().ptr, suffix);
}
return result;
}
/* 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.
/* 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.
/* 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.
/* 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.
/* 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.
bool isAncestorPackageOf(const Package * const pkg) const;
- void semantic(Scope *);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
void accept(Visitor *v) { v->visit(this); }
bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise.
Module *parse(); // syntactic parse
void importAll(Scope *sc);
- void semantic(Scope *); // semantic analysis
- void semantic2(Scope *); // pass 2 semantic analysis
- void semantic3(Scope *); // pass 3 semantic analysis
int needModuleInfo();
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
bool isPackageAccessible(Package *p, Prot protection, int flags = 0);
/* 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.
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-Expression *semantic(Expression *e, Scope *sc);
-Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
-Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
-Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
/***************************** Type *****************************/
return (unsigned)size(Loc());
}
-Type *Type::semantic(Loc loc, Scope *)
-{
- if (ty == Tint128 || ty == Tuns128)
- {
- error(loc, "cent and ucent types not implemented");
- return terror;
- }
-
- return merge();
-}
-
Type *Type::trySemantic(Loc loc, Scope *sc)
{
//printf("+trySemantic(%s) %d\n", toChars(), global.errors);
unsigned errors = global.startGagging();
- Type *t = semantic(loc, sc);
+ Type *t = typeSemantic(this, loc, sc);
if (global.endGagging(errors) || t->ty == Terror) // if any errors happened
{
t = NULL;
{
e = new StringExp(loc, (char *)deco, strlen(deco));
Scope sc;
- e = ::semantic(e, &sc);
+ e = expressionSemantic(e, &sc);
}
}
else if (ident == Id::stringof)
const char *s = toChars();
e = new StringExp(loc, const_cast<char *>(s), strlen(s));
Scope sc;
- e = ::semantic(e, &sc);
+ e = expressionSemantic(e, &sc);
}
else if (flag && this != Type::terror)
{
if (this != Type::terror)
{
if (s)
- error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars());
+ error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toChars());
else
- error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
+ error(loc, "no property `%s` for type `%s`", ident->toChars(), toChars());
}
e = new ErrorExp();
}
Lreturn:
if (e)
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
*/
e = build_overload(e->loc, sc, e, NULL, fd);
e = new DotIdExp(e->loc, e, ident);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
--nest;
return e;
}
void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
{
//printf("Type::resolve() %s, %d\n", toChars(), ty);
- Type *t = semantic(loc, sc);
+ Type *t = typeSemantic(this, loc, sc);
*pt = t;
*pe = NULL;
*ps = NULL;
return Type::dotExp(sc, e, ident, flag);
}
if (!(flag & 1) || e)
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
return new TypeVector(basetype->syntaxCopy());
}
-Type *TypeVector::semantic(Loc loc, Scope *sc)
-{
- unsigned int errors = global.errors;
- basetype = basetype->semantic(loc, sc);
- if (errors != global.errors)
- return terror;
- basetype = basetype->toBasetype()->mutableOf();
- if (basetype->ty != Tsarray)
- {
- error(loc, "T in __vector(T) must be a static array, not %s", basetype->toChars());
- return terror;
- }
- TypeSArray *t = (TypeSArray *)basetype;
- int sz = (int)t->size(loc);
- switch (target.isVectorTypeSupported(sz, t->nextOf()))
- {
- case 0: // valid
- break;
- case 1: // no support at all
- error(loc, "SIMD vector types not supported on this platform");
- return terror;
- case 2: // invalid base type
- error(loc, "vector type %s is not supported on this platform", toChars());
- return terror;
- case 3: // invalid size
- error(loc, "%d byte vector type %s is not supported on this platform", sz, toChars());
- return terror;
- default:
- assert(0);
- }
- return merge();
-}
-
TypeBasic *TypeVector::elementType()
{
assert(basetype->ty == Tsarray);
* __vector(float[4]), and a type paint won't do.
*/
e = new AddrExp(e->loc, e);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = e->castTo(sc, basetype->nextOf()->pointerTo());
return e;
}
//e = e->castTo(sc, basetype);
// Keep lvalue-ness
e = new VectorArrayExp(e->loc, e);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (ident == Id::_init || ident == Id::offsetof || ident == Id::stringof || ident == Id::__xalignof)
e = Type::dotExp(sc, e, ident, flag);
if (!(flag & 1) || e)
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
return next->alignsize();
}
-/**************************
- * This evaluates exp while setting length to be the number
- * of elements in the tuple t.
- */
-Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
-{
- if (t->ty == Ttuple)
- {
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- sc = sc->startCTFE();
- exp = ::semantic(exp, sc);
- sc = sc->endCTFE();
-
- sc->pop();
- }
- else
- {
- sc = sc->startCTFE();
- exp = ::semantic(exp, sc);
- sc = sc->endCTFE();
- }
-
- return exp;
-}
-
-Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
-{
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- sc = sc->startCTFE();
- exp = ::semantic(exp, sc);
- sc = sc->endCTFE();
-
- sc->pop();
- return exp;
-}
-
void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
{
//printf("TypeSArray::resolve() %s\n", toChars());
sym->parent = sc->scopesym;
sc = sc->push(sym);
sc = sc->startCTFE();
- dim = ::semantic(dim, sc);
+ dim = expressionSemantic(dim, sc);
sc = sc->endCTFE();
sc = sc->pop();
}
}
-Type *TypeSArray::semantic(Loc loc, Scope *sc)
-{
- //printf("TypeSArray::semantic() %s\n", toChars());
-
- Type *t;
- Expression *e;
- Dsymbol *s;
- next->resolve(loc, sc, &e, &t, &s);
- if (dim && s && s->isTupleDeclaration())
- { TupleDeclaration *sd = s->isTupleDeclaration();
-
- dim = semanticLength(sc, sd, dim);
- dim = dim->ctfeInterpret();
- uinteger_t d = dim->toUInteger();
-
- if (d >= sd->objects->length)
- { error(loc, "tuple index %llu exceeds %u", d, sd->objects->length);
- return Type::terror;
- }
- RootObject *o = (*sd->objects)[(size_t)d];
- if (o->dyncast() != DYNCAST_TYPE)
- { error(loc, "%s is not a type", toChars());
- return Type::terror;
- }
- t = ((Type *)o)->addMod(this->mod);
- return t;
- }
-
- Type *tn = next->semantic(loc, sc);
- if (tn->ty == Terror)
- return terror;
-
- Type *tbn = tn->toBasetype();
-
- if (dim)
- {
- unsigned int errors = global.errors;
- dim = semanticLength(sc, tbn, dim);
- if (errors != global.errors)
- goto Lerror;
-
- dim = dim->optimize(WANTvalue);
- dim = dim->ctfeInterpret();
- if (dim->op == TOKerror)
- goto Lerror;
- errors = global.errors;
- dinteger_t d1 = dim->toInteger();
- if (errors != global.errors)
- goto Lerror;
-
- dim = dim->implicitCastTo(sc, tsize_t);
- dim = dim->optimize(WANTvalue);
- if (dim->op == TOKerror)
- goto Lerror;
- errors = global.errors;
- dinteger_t d2 = dim->toInteger();
- if (errors != global.errors)
- goto Lerror;
-
- if (dim->op == TOKerror)
- goto Lerror;
-
- if (d1 != d2)
- {
- Loverflow:
- error(loc, "%s size %llu * %llu exceeds 0x%llx size limit for static array",
- toChars(), (unsigned long long)tbn->size(loc), (unsigned long long)d1, target.maxStaticDataSize);
- goto Lerror;
- }
-
- Type *tbx = tbn->baseElemOf();
- if ((tbx->ty == Tstruct && !((TypeStruct *)tbx)->sym->members) ||
- (tbx->ty == Tenum && !((TypeEnum *)tbx)->sym->members))
- {
- /* To avoid meaningless error message, skip the total size limit check
- * when the bottom of element type is opaque.
- */
- }
- else if (tbn->isTypeBasic() ||
- tbn->ty == Tpointer ||
- tbn->ty == Tarray ||
- tbn->ty == Tsarray ||
- tbn->ty == Taarray ||
- (tbn->ty == Tstruct && (((TypeStruct *)tbn)->sym->sizeok == SIZEOKdone)) ||
- tbn->ty == Tclass)
- {
- /* Only do this for types that don't need to have semantic()
- * run on them for the size, since they may be forward referenced.
- */
- bool overflow = false;
- if (mulu(tbn->size(loc), d2, overflow) >= target.maxStaticDataSize || overflow)
- goto Loverflow;
- }
- }
- switch (tbn->ty)
- {
- case Ttuple:
- { // Index the tuple to get the type
- assert(dim);
- TypeTuple *tt = (TypeTuple *)tbn;
- uinteger_t d = dim->toUInteger();
-
- if (d >= tt->arguments->length)
- { error(loc, "tuple index %llu exceeds %u", d, tt->arguments->length);
- goto Lerror;
- }
- Type *telem = (*tt->arguments)[(size_t)d]->type;
- return telem->addMod(this->mod);
- }
- case Tfunction:
- case Tnone:
- error(loc, "can't have array of %s", tbn->toChars());
- goto Lerror;
- default:
- break;
- }
- if (tbn->isscope())
- { error(loc, "cannot have array of scope %s", tbn->toChars());
- goto Lerror;
- }
-
- /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
- * and const(T)[3] become const(T[3])
- */
- next = tn;
- transitive();
- t = addMod(tn->mod);
-
- return t->merge();
-
-Lerror:
- return Type::terror;
-}
-
Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
{
if (ident == Id::length)
e = TypeArray::dotExp(sc, e, ident, flag);
}
if (!(flag & 1) || e)
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
return target.ptrsize;
}
-Type *TypeDArray::semantic(Loc loc, Scope *sc)
-{
- Type *tn = next->semantic(loc,sc);
- Type *tbn = tn->toBasetype();
- switch (tbn->ty)
- {
- case Ttuple:
- return tbn;
- case Tfunction:
- case Tnone:
- error(loc, "can't have array of %s", tbn->toChars());
- return Type::terror;
- case Terror:
- return Type::terror;
- default:
- break;
- }
- if (tn->isscope())
- { error(loc, "cannot have array of scope %s", tn->toChars());
- return Type::terror;
- }
- next = tn;
- transitive();
- return merge();
-}
-
void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
{
//printf("TypeDArray::resolve() %s\n", toChars());
return target.ptrsize;
}
-Type *TypeAArray::semantic(Loc loc, Scope *sc)
-{
- //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
- if (deco)
- return this;
-
- this->loc = loc;
- this->sc = sc;
- if (sc)
- sc->setNoFree();
-
- // Deal with the case where we thought the index was a type, but
- // in reality it was an expression.
- if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray ||
- index->ty == Ttypeof || index->ty == Treturn)
- {
- Expression *e;
- Type *t;
- Dsymbol *s;
-
- index->resolve(loc, sc, &e, &t, &s);
- if (e)
- {
- // It was an expression -
- // Rewrite as a static array
- TypeSArray *tsa = new TypeSArray(next, e);
- return tsa->semantic(loc, sc);
- }
- else if (t)
- index = t->semantic(loc, sc);
- else
- {
- index->error(loc, "index is not a type or an expression");
- return Type::terror;
- }
- }
- else
- index = index->semantic(loc,sc);
- index = index->merge2();
-
- if (index->nextOf() && !index->nextOf()->isImmutable())
- {
- index = index->constOf()->mutableOf();
- }
-
- switch (index->toBasetype()->ty)
- {
- case Tfunction:
- case Tvoid:
- case Tnone:
- case Ttuple:
- error(loc, "can't have associative array key of %s", index->toBasetype()->toChars());
- /* fall through */
- case Terror:
- return Type::terror;
- default:
- break;
- }
- Type *tbase = index->baseElemOf();
- while (tbase->ty == Tarray)
- tbase = tbase->nextOf()->baseElemOf();
- if (tbase->ty == Tstruct)
- {
- /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
- */
- StructDeclaration *sd = ((TypeStruct *)tbase)->sym;
- if (sd->semanticRun < PASSsemanticdone)
- sd->semantic(NULL);
-
- // duplicate a part of StructDeclaration::semanticTypeInfoMembers
- //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd->xeq, sd->xerreq, sd->xhash);
- if (sd->xeq &&
- sd->xeq->_scope &&
- sd->xeq->semanticRun < PASSsemantic3done)
- {
- unsigned errors = global.startGagging();
- sd->xeq->semantic3(sd->xeq->_scope);
- if (global.endGagging(errors))
- sd->xeq = sd->xerreq;
- }
-
- const char *s = (index->toBasetype()->ty != Tstruct) ? "bottom of " : "";
- if (!sd->xeq)
- {
- // If sd->xhash != NULL:
- // sd or its fields have user-defined toHash.
- // AA assumes that its result is consistent with bitwise equality.
- // else:
- // bitwise equality & hashing
- }
- else if (sd->xeq == sd->xerreq)
- {
- if (search_function(sd, Id::eq))
- {
- error(loc, "%sAA key type %s does not have 'bool opEquals(ref const %s) const'",
- s, sd->toChars(), sd->toChars());
- }
- else
- {
- error(loc, "%sAA key type %s does not support const equality",
- s, sd->toChars());
- }
- return Type::terror;
- }
- else if (!sd->xhash)
- {
- if (search_function(sd, Id::eq))
- {
- error(loc, "%sAA key type %s should have 'size_t toHash() const nothrow @safe' if opEquals defined",
- s, sd->toChars());
- }
- else
- {
- error(loc, "%sAA key type %s supports const equality but doesn't support const hashing",
- s, sd->toChars());
- }
- return Type::terror;
- }
- else
- {
- // defined equality & hashing
- assert(sd->xeq && sd->xhash);
-
- /* xeq and xhash may be implicitly defined by compiler. For example:
- * struct S { int[] arr; }
- * With 'arr' field equality and hashing, compiler will implicitly
- * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
- */
- }
- }
- else if (tbase->ty == Tclass && !((TypeClass *)tbase)->sym->isInterfaceDeclaration())
- {
- ClassDeclaration *cd = ((TypeClass *)tbase)->sym;
- if (cd->semanticRun < PASSsemanticdone)
- cd->semantic(NULL);
-
- if (!ClassDeclaration::object)
- {
- error(Loc(), "missing or corrupt object.d");
- fatal();
- }
-
- static FuncDeclaration *feq = NULL;
- static FuncDeclaration *fcmp = NULL;
- static FuncDeclaration *fhash = NULL;
- if (!feq) feq = search_function(ClassDeclaration::object, Id::eq)->isFuncDeclaration();
- if (!fcmp) fcmp = search_function(ClassDeclaration::object, Id::cmp)->isFuncDeclaration();
- if (!fhash) fhash = search_function(ClassDeclaration::object, Id::tohash)->isFuncDeclaration();
- assert(fcmp && feq && fhash);
-
- if (feq->vtblIndex < (int)cd->vtbl.length && cd->vtbl[feq ->vtblIndex] == feq)
- {
- if (fcmp->vtblIndex < (int)cd->vtbl.length && cd->vtbl[fcmp->vtblIndex] != fcmp)
- {
- const char *s = (index->toBasetype()->ty != Tclass) ? "bottom of " : "";
- error(loc, "%sAA key type %s now requires equality rather than comparison",
- s, cd->toChars());
- errorSupplemental(loc, "Please override Object.opEquals and toHash.");
- }
- }
- }
- next = next->semantic(loc,sc)->merge2();
- transitive();
-
- switch (next->toBasetype()->ty)
- {
- case Tfunction:
- case Tvoid:
- case Tnone:
- case Ttuple:
- error(loc, "can't have associative array of %s", next->toChars());
- /* fall through */
- case Terror:
- return Type::terror;
- }
- if (next->isscope())
- { error(loc, "cannot have array of scope %s", next->toChars());
- return Type::terror;
- }
- return merge();
-}
-
void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
{
//printf("TypeAArray::resolve() %s\n", toChars());
return t;
}
-Type *TypePointer::semantic(Loc loc, Scope *sc)
-{
- //printf("TypePointer::semantic() %s\n", toChars());
- if (deco)
- return this;
- Type *n = next->semantic(loc, sc);
- switch (n->toBasetype()->ty)
- {
- case Ttuple:
- error(loc, "can't have pointer to %s", n->toChars());
- /* fall through */
- case Terror:
- return Type::terror;
- default:
- break;
- }
- if (n != next)
- {
- deco = NULL;
- }
- next = n;
- if (next->ty != Tfunction)
- { transitive();
- return merge();
- }
- deco = merge()->deco;
- /* Don't return merge(), because arg identifiers and default args
- * can be different
- * even though the types match
- */
- return this;
-}
-
-
d_uns64 TypePointer::size(Loc)
{
return target.ptrsize;
return t;
}
-Type *TypeReference::semantic(Loc loc, Scope *sc)
-{
- //printf("TypeReference::semantic()\n");
- Type *n = next->semantic(loc, sc);
- if (n != next)
- deco = NULL;
- next = n;
- transitive();
- return merge();
-}
-
-
d_uns64 TypeReference::size(Loc)
{
return target.ptrsize;
// If t1n is forward referenced:
ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
if (cd->semanticRun < PASSsemanticdone && !cd->isBaseInfoComplete())
- cd->semantic(NULL);
+ dsymbolSemantic(cd, NULL);
if (!cd->isBaseInfoComplete())
{
return 3; // forward references
return 2;
}
-Type *TypeFunction::semantic(Loc loc, Scope *sc)
-{
- if (deco) // if semantic() already run
- {
- //printf("already done\n");
- return this;
- }
- //printf("TypeFunction::semantic() this = %p\n", this);
- //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs);
-
- bool errors = false;
-
- if (inuse > global.recursionLimit)
- {
- inuse = 0;
- ::error(loc, "recursive type");
- return Type::terror;
- }
-
- /* Copy in order to not mess up original.
- * This can produce redundant copies if inferring return type,
- * as semantic() will get called again on this.
- */
- TypeFunction *tf = copy()->toTypeFunction();
- if (parameterList.parameters)
- {
- tf->parameterList.parameters = parameterList.parameters->copy();
- for (size_t i = 0; i < parameterList.parameters->length; i++)
- {
- void *pp = mem.xmalloc(sizeof(Parameter));
- Parameter *p = (Parameter *)memcpy(pp, (void *)(*parameterList.parameters)[i],
- sizeof(Parameter));
- (*tf->parameterList.parameters)[i] = p;
- }
- }
-
- if (sc->stc & STCpure)
- tf->purity = PUREfwdref;
- if (sc->stc & STCnothrow)
- tf->isnothrow = true;
- if (sc->stc & STCnogc)
- tf->isnogc = true;
- if (sc->stc & STCref)
- tf->isref = true;
- if (sc->stc & STCreturn)
- tf->isreturn = true;
- if (sc->stc & STCscope)
- tf->isscope = true;
- if (sc->stc & STCscopeinferred)
- tf->isscopeinferred = true;
-
-// if ((sc->stc & (STCreturn | STCref)) == STCreturn)
-// tf->isscope = true; // return by itself means 'return scope'
-
- if (tf->trust == TRUSTdefault)
- {
- if (sc->stc & STCsafe)
- tf->trust = TRUSTsafe;
- if (sc->stc & STCsystem)
- tf->trust = TRUSTsystem;
- if (sc->stc & STCtrusted)
- tf->trust = TRUSTtrusted;
- }
-
- if (sc->stc & STCproperty)
- tf->isproperty = true;
-
- tf->linkage = sc->linkage;
- bool wildreturn = false;
- if (tf->next)
- {
- sc = sc->push();
- sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
- tf->next = tf->next->semantic(loc, sc);
- sc = sc->pop();
- errors |= tf->checkRetType(loc);
- if (tf->next->isscope() && !(sc->flags & SCOPEctor))
- {
- error(loc, "functions cannot return scope %s", tf->next->toChars());
- errors = true;
- }
- if (tf->next->hasWild())
- wildreturn = true;
-
- if (tf->isreturn && !tf->isref && !tf->next->hasPointers())
- {
- error(loc, "function type '%s' has 'return' but does not return any indirections", tf->toChars());
- }
- }
-
- unsigned char wildparams = 0;
- if (tf->parameterList.parameters)
- {
- /* Create a scope for evaluating the default arguments for the parameters
- */
- Scope *argsc = sc->push();
- argsc->stc = 0; // don't inherit storage class
- argsc->protection = Prot(Prot::public_);
- argsc->func = NULL;
-
- size_t dim = tf->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = tf->parameterList[i];
- inuse++;
- fparam->type = fparam->type->semantic(loc, argsc);
- inuse--;
-
- if (fparam->type->ty == Terror)
- {
- errors = true;
- continue;
- }
-
- fparam->type = fparam->type->addStorageClass(fparam->storageClass);
-
- if (fparam->storageClass & (STCauto | STCalias | STCstatic))
- {
- if (!fparam->type)
- continue;
- }
-
- Type *t = fparam->type->toBasetype();
-
- if (t->ty == Tfunction)
- {
- error(loc, "cannot have parameter of function type %s", fparam->type->toChars());
- errors = true;
- }
- else if (!(fparam->storageClass & (STCref | STCout)) &&
- (t->ty == Tstruct || t->ty == Tsarray || t->ty == Tenum))
- {
- Type *tb2 = t->baseElemOf();
- if ((tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members) ||
- (tb2->ty == Tenum && !((TypeEnum *)tb2)->sym->memtype))
- {
- error(loc, "cannot have parameter of opaque type %s by value", fparam->type->toChars());
- errors = true;
- }
- }
- else if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
- {
- error(loc, "cannot have parameter of type %s", fparam->type->toChars());
- errors = true;
- }
-
- if ((fparam->storageClass & (STCref | STCwild)) == (STCref | STCwild))
- {
- // 'ref inout' implies 'return'
- fparam->storageClass |= STCreturn;
- }
-
- if (fparam->storageClass & STCreturn)
- {
- if (fparam->storageClass & (STCref | STCout))
- {
- // Disabled for the moment awaiting improvement to allow return by ref
- // to be transformed into return by scope.
- if (0 && !tf->isref)
- {
- StorageClass stc = fparam->storageClass & (STCref | STCout);
- error(loc, "parameter %s is 'return %s' but function does not return by ref",
- fparam->ident ? fparam->ident->toChars() : "",
- stcToChars(stc));
- errors = true;
- }
- }
- else
- {
- fparam->storageClass |= STCscope; // 'return' implies 'scope'
- if (tf->isref)
- {
- }
- else if (!tf->isref && tf->next && !tf->next->hasPointers())
- {
- error(loc, "parameter %s is 'return' but function does not return any indirections",
- fparam->ident ? fparam->ident->toChars() : "");
- errors = true;
- }
- }
- }
-
- if (fparam->storageClass & (STCref | STClazy))
- {
- }
- else if (fparam->storageClass & STCout)
- {
- if (unsigned char m = fparam->type->mod & (MODimmutable | MODconst | MODwild))
- {
- error(loc, "cannot have %s out parameter of type %s", MODtoChars(m), t->toChars());
- errors = true;
- }
- else
- {
- Type *tv = t;
- while (tv->ty == Tsarray)
- tv = tv->nextOf()->toBasetype();
- if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->noDefaultCtor)
- {
- error(loc, "cannot have out parameter of type %s because the default construction is disabled",
- fparam->type->toChars());
- errors = true;
- }
- }
- }
-
- if (fparam->storageClass & STCscope && !fparam->type->hasPointers() && fparam->type->ty != Ttuple)
- {
- fparam->storageClass &= ~STCscope;
- if (!(fparam->storageClass & STCref))
- fparam->storageClass &= ~STCreturn;
- }
-
- if (t->hasWild())
- {
- wildparams |= 1;
- //if (tf->next && !wildreturn)
- // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')");
- }
-
- if (fparam->defaultArg)
- {
- Expression *e = fparam->defaultArg;
- if (fparam->storageClass & (STCref | STCout))
- {
- e = ::semantic(e, argsc);
- e = resolveProperties(argsc, e);
- }
- else
- {
- e = inferType(e, fparam->type);
- Initializer *iz = new ExpInitializer(e->loc, e);
- iz = ::semantic(iz, argsc, fparam->type, INITnointerpret);
- e = initializerToExpression(iz);
- }
- if (e->op == TOKfunction) // see Bugzilla 4820
- {
- FuncExp *fe = (FuncExp *)e;
- // Replace function literal with a function symbol,
- // since default arg expression must be copied when used
- // and copying the literal itself is wrong.
- e = new VarExp(e->loc, fe->fd, false);
- e = new AddrExp(e->loc, e);
- e = ::semantic(e, argsc);
- }
- e = e->implicitCastTo(argsc, fparam->type);
-
- // default arg must be an lvalue
- if (fparam->storageClass & (STCout | STCref))
- e = e->toLvalue(argsc, e);
-
- fparam->defaultArg = e;
- if (e->op == TOKerror)
- errors = true;
- }
-
- /* If fparam after semantic() turns out to be a tuple, the number of parameters may
- * change.
- */
- if (t->ty == Ttuple)
- {
- /* TypeFunction::parameter also is used as the storage of
- * Parameter objects for FuncDeclaration. So we should copy
- * the elements of TypeTuple::arguments to avoid unintended
- * sharing of Parameter object among other functions.
- */
- TypeTuple *tt = (TypeTuple *)t;
- if (tt->arguments && tt->arguments->length)
- {
- /* Propagate additional storage class from tuple parameters to their
- * element-parameters.
- * Make a copy, as original may be referenced elsewhere.
- */
- size_t tdim = tt->arguments->length;
- Parameters *newparams = new Parameters();
- newparams->setDim(tdim);
- for (size_t j = 0; j < tdim; j++)
- {
- Parameter *narg = (*tt->arguments)[j];
-
- // Bugzilla 12744: If the storage classes of narg
- // conflict with the ones in fparam, it's ignored.
- StorageClass stc = fparam->storageClass | narg->storageClass;
- StorageClass stc1 = fparam->storageClass & (STCref | STCout | STClazy);
- StorageClass stc2 = narg->storageClass & (STCref | STCout | STClazy);
- if (stc1 && stc2 && stc1 != stc2)
- {
- OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STCref) ? (fparam->storageClass & STCauto) : 0));
- OutBuffer buf2; stcToBuffer(&buf2, stc2);
-
- error(loc, "incompatible parameter storage classes '%s' and '%s'",
- buf1.peekChars(), buf2.peekChars());
- errors = true;
- stc = stc1 | (stc & ~(STCref | STCout | STClazy));
- }
-
- (*newparams)[j] = new Parameter(
- stc, narg->type, narg->ident, narg->defaultArg, narg->userAttribDecl);
- }
- fparam->type = new TypeTuple(newparams);
- }
- fparam->storageClass = 0;
-
- /* Reset number of parameters, and back up one to do this fparam again,
- * now that it is a tuple
- */
- dim = tf->parameterList.length();
- i--;
- continue;
- }
-
- /* Resolve "auto ref" storage class to be either ref or value,
- * based on the argument matching the parameter
- */
- if (fparam->storageClass & STCauto)
- {
- if (fargs && i < fargs->length && (fparam->storageClass & STCref))
- {
- Expression *farg = (*fargs)[i];
- if (farg->isLvalue())
- ; // ref parameter
- else
- fparam->storageClass &= ~STCref; // value parameter
- fparam->storageClass &= ~STCauto; // Bugzilla 14656
- fparam->storageClass |= STCautoref;
- }
- else
- {
- error(loc, "'auto' can only be used as part of 'auto ref' for template function parameters");
- errors = true;
- }
- }
-
- // Remove redundant storage classes for type, they are already applied
- fparam->storageClass &= ~(STC_TYPECTOR | STCin);
- }
- argsc->pop();
- }
- if (tf->isWild())
- wildparams |= 2;
-
- if (wildreturn && !wildparams)
- {
- error(loc, "inout on return means inout must be on a parameter as well for %s", toChars());
- errors = true;
- }
- tf->iswild = wildparams;
-
- if (tf->isproperty && (tf->parameterList.varargs != VARARGnone || tf->parameterList.length() > 2))
- {
- error(loc, "properties can only have zero, one, or two parameter");
- errors = true;
- }
-
- if (tf->parameterList.varargs == VARARGvariadic && tf->linkage != LINKd && tf->parameterList.length() == 0)
- {
- error(loc, "variadic functions with non-D linkage must have at least one parameter");
- errors = true;
- }
-
- if (errors)
- return terror;
-
- if (tf->next)
- tf->deco = tf->merge()->deco;
-
- /* Don't return merge(), because arg identifiers and default args
- * can be different
- * even though the types match
- */
- return tf;
-}
-
bool TypeFunction::checkRetType(Loc loc)
{
Type *tb = next->toBasetype();
return t;
}
-Type *TypeDelegate::semantic(Loc loc, Scope *sc)
-{
- //printf("TypeDelegate::semantic() %s\n", toChars());
- if (deco) // if semantic() already run
- {
- //printf("already done\n");
- return this;
- }
- next = next->semantic(loc,sc);
- if (next->ty != Tfunction)
- return terror;
-
- /* In order to deal with Bugzilla 4028, perhaps default arguments should
- * be removed from next before the merge.
- */
-
- /* Don't return merge(), because arg identifiers and default args
- * can be different
- * even though the types match
- */
- deco = merge()->deco;
- return this;
-}
-
Type *TypeDelegate::addStorageClass(StorageClass stc)
{
TypeDelegate *t = (TypeDelegate*)Type::addStorageClass(stc);
if (ident == Id::ptr)
{
e = new DelegatePtrExp(e->loc, e);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
else if (ident == Id::funcptr)
{
return new ErrorExp();
}
e = new DelegateFuncptrExp(e->loc, e);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
}
else
{
return tt;
}
-Type *TypeTraits::semantic(Loc, Scope *sc)
-{
- if (ty == Terror)
- return this;
-
- const int inAlias = (sc->flags & SCOPEalias) != 0;
- if (exp->ident != Id::allMembers &&
- exp->ident != Id::derivedMembers &&
- exp->ident != Id::getMember &&
- exp->ident != Id::parent &&
- exp->ident != Id::child &&
- exp->ident != Id::getOverloads &&
- exp->ident != Id::getVirtualFunctions &&
- exp->ident != Id::getVirtualMethods &&
- exp->ident != Id::getAttributes &&
- exp->ident != Id::getUnitTests &&
- exp->ident != Id::getAliasThis)
- {
- static const char *ctxt[2] = {"as type", "in alias"};
- ::error(loc, "trait `%s` is either invalid or not supported %s",
- exp->ident->toChars(), ctxt[inAlias]);
- ty = Terror;
- return this;
- }
-
- Type *result = NULL;
-
- if (Expression *e = semanticTraits(exp, sc))
- {
- switch (e->op)
- {
- case TOKdotvar:
- sym = ((DotVarExp *)e)->var;
- break;
- case TOKvar:
- sym = ((VarExp *)e)->var;
- break;
- case TOKfunction:
- {
- FuncExp *fe = (FuncExp *)e;
- if (fe->td)
- sym = fe->td;
- else
- sym = fe->fd;
- break;
- }
- case TOKdottd:
- sym = ((DotTemplateExp*)e)->td;
- break;
- case TOKdsymbol:
- sym = ((DsymbolExp *)e)->s;
- break;
- case TOKtemplate:
- sym = ((TemplateExp *)e)->td;
- break;
- case TOKscope:
- sym = ((ScopeExp *)e)->sds;
- break;
- case TOKtuple:
- {
- TupleExp *te = e->toTupleExp();
- Objects *elems = new Objects;
- elems->setDim(te->exps->length);
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *src = (*te->exps)[i];
- switch (src->op)
- {
- case TOKtype:
- (*elems)[i] = ((TypeExp *)src)->type;
- break;
- case TOKdottype:
- (*elems)[i] = ((DotTypeExp *)src)->type;
- break;
- case TOKoverloadset:
- (*elems)[i] = ((OverExp *)src)->type;
- break;
- default:
- if (Dsymbol *sym = isDsymbol(src))
- (*elems)[i] = sym;
- else
- (*elems)[i] = src;
- }
- }
- TupleDeclaration *td = new TupleDeclaration(e->loc,
- Identifier::generateId("__aliastup"), elems);
- sym = td;
- break;
- }
- case TOKdottype:
- result = isType(((DotTypeExp *)e)->sym);
- break;
- case TOKtype:
- result = ((TypeExp *)e)->type;
- break;
- case TOKoverloadset:
- result = ((OverExp *)e)->type;
- break;
- default:
- break;
- }
- }
-
- if (result)
- result = result->addMod(mod);
- if (!inAlias && !result)
- {
- if (!global.errors)
- ::error(loc, "`%s` does not give a valid type", toChars());
- return Type::terror;
- }
-
- return result;
-}
-
void TypeTraits::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
{
*pt = NULL;
*pe = NULL;
*ps = NULL;
- if (Type *t = semantic(loc, sc))
+ if (Type *t = typeSemantic(this, loc, sc))
*pt = t;
else if (sym)
*ps = sym;
else if (sindex)
eindex = ::resolve(loc, sc, sindex, false);
Expression *e = new IndexExp(loc, ::resolve(loc, sc, s, false), eindex);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
resolveExp(e, pt, pe, ps);
return;
}
return;
}
sc = sc->startCTFE();
- eindex = ::semantic(eindex, sc);
+ eindex = expressionSemantic(eindex, sc);
sc = sc->endCTFE();
eindex = eindex->ctfeInterpret();
*pe = isExpression(o);
if (*pt)
- *pt = (*pt)->semantic(loc, sc);
+ *pt = typeSemantic(*pt, loc, sc);
if (*pe)
resolveExp(*pe, pt, pe, ps);
}
assert(ex);
ex = typeToExpressionHelper(this, ex, i + 1);
- ex = ::semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
resolveExp(ex, pt, pe, ps);
return;
}
// https://issues.dlang.org/show_bug.cgi?id=19913
// v->type would be null if it is a forward referenced member.
if (v->type == NULL)
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
if (v->storage_class & (STCconst | STCimmutable | STCmanifest) ||
v->type->isConst() || v->type->isImmutable())
{
e = new VarExp(loc, s->isDeclaration(), true);
e = typeToExpressionHelper(this, e, i);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
resolveExp(e, pt, pe, ps);
return;
}
assert(id->dyncast() == DYNCAST_IDENTIFIER);
sm = s->search_correct((Identifier *)id);
if (sm)
- error(loc, "identifier '%s' of '%s' is not defined, did you mean %s '%s'?",
+ error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?",
id->toChars(), toChars(), sm->kind(), sm->toChars());
else
- error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars());
+ error(loc, "identifier `%s` of `%s` is not defined", id->toChars(), toChars());
}
*pe = new ErrorExp();
}
(!v->type->deco && v->inuse))
{
if (v->inuse) // Bugzilla 9494
- error(loc, "circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ error(loc, "circular reference to %s `%s`", v->kind(), v->toPrettyChars());
else
- error(loc, "forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ error(loc, "forward reference to %s `%s`", v->kind(), v->toPrettyChars());
*pt = Type::terror;
return;
}
{
//printf("'%s' is a function literal\n", fld->toChars());
*pe = new FuncExp(loc, fld);
- *pe = ::semantic(*pe, sc);
+ *pe = expressionSemantic(*pe, sc);
return;
}
L1:
if (t->ty == Tinstance && t != this && !t->deco)
{
if (!((TypeInstance *)t)->tempinst->errors)
- error(loc, "forward reference to '%s'", t->toChars());
+ error(loc, "forward reference to `%s`", t->toChars());
*pt = Type::terror;
return;
}
return s;
}
-Type *TypeIdentifier::semantic(Loc loc, Scope *sc)
-{
- Type *t;
- Expression *e;
- Dsymbol *s;
-
- //printf("TypeIdentifier::semantic(%s)\n", toChars());
- resolve(loc, sc, &e, &t, &s);
- if (t)
- {
- //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
- t = t->addMod(mod);
- }
- else
- {
- if (s)
- {
- s->error(loc, "is used as a type");
- //halt();
- }
- else
- error(loc, "%s is used as a type", toChars());
- t = terror;
- }
- //t->print();
- return t;
-}
-
/***************************** TypeInstance *****************************/
TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
*pt = NULL;
*ps = NULL;
//printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, tempinst->toChars());
- tempinst->semantic(sc);
+ dsymbolSemantic(tempinst, sc);
if (!global.gag && tempinst->errors)
{
*pt = terror;
//if (*pt) printf("pt = '%s'\n", (*pt)->toChars());
}
-Type *TypeInstance::semantic(Loc loc, Scope *sc)
-{
- Type *t;
- Expression *e;
- Dsymbol *s;
-
- //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
- {
- unsigned errors = global.errors;
- resolve(loc, sc, &e, &t, &s);
- // if we had an error evaluating the symbol, suppress further errors
- if (!t && errors != global.errors)
- return terror;
- }
-
- if (!t)
- {
- if (!e && s && s->errors)
- {
- // if there was an error evaluating the symbol, it might actually
- // be a type. Avoid misleading error messages.
- error(loc, "%s had previous errors", toChars());
- }
- else
- error(loc, "%s is used as a type", toChars());
- t = terror;
- }
- return t;
-}
-
Dsymbol *TypeInstance::toDsymbol(Scope *sc)
{
Type *t;
*/
Scope *sc2 = sc->push();
sc2->intypeof = 1;
- Expression *exp2 = ::semantic(exp, sc2);
+ Expression *exp2 = expressionSemantic(exp, sc2);
exp2 = resolvePropertiesOnly(sc2, exp2);
sc2->pop();
else
{
Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
resolveExp(e, pt, pe, ps);
}
}
return;
}
-Type *TypeTypeof::semantic(Loc loc, Scope *sc)
-{
- //printf("TypeTypeof::semantic() %s\n", toChars());
-
- Expression *e;
- Type *t;
- Dsymbol *s;
- resolve(loc, sc, &e, &t, &s);
- if (s && (t = s->getType()) != NULL)
- t = t->addMod(mod);
- if (!t)
- {
- error(loc, "%s is used as a type", toChars());
- t = Type::terror;
- }
- return t;
-}
-
d_uns64 TypeTypeof::size(Loc loc)
{
if (exp->type)
else
{
Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
resolveExp(e, pt, pe, ps);
}
}
return;
}
-Type *TypeReturn::semantic(Loc loc, Scope *sc)
-{
- //printf("TypeReturn::semantic() %s\n", toChars());
-
- Expression *e;
- Type *t;
- Dsymbol *s;
- resolve(loc, sc, &e, &t, &s);
- if (s && (t = s->getType()) != NULL)
- t = t->addMod(mod);
- if (!t)
- {
- error(loc, "%s is used as a type", toChars());
- t = Type::terror;
- }
- return t;
-}
-
/***************************** TypeEnum *****************************/
TypeEnum::TypeEnum(EnumDeclaration *sym)
return this;
}
-Type *TypeEnum::semantic(Loc, Scope *)
-{
- //printf("TypeEnum::semantic() %s\n", toChars());
- if (deco)
- return this;
- return merge();
-}
-
d_uns64 TypeEnum::size(Loc loc)
{
return sym->getMemtype(loc)->size(loc);
return getProperty(e->loc, ident, flag & 1);
if (sym->semanticRun < PASSsemanticdone)
- sym->semantic(NULL);
+ dsymbolSemantic(sym, NULL);
if (!sym->members)
{
if (sym->isSpecial())
}
else if (!(flag & 1))
{
- sym->error("is forward referenced when looking for '%s'", ident->toChars());
+ sym->error("is forward referenced when looking for `%s`", ident->toChars());
e = new ErrorExp();
}
else
if (!(flag & 1) && !res)
{
if (Dsymbol *ns = sym->search_correct(ident))
- e->error("no property '%s' for type '%s'. Did you mean '%s.%s' ?",
+ e->error("no property `%s` for type `%s`. Did you mean `%s.%s` ?",
ident->toChars(), toChars(), toChars(), ns->toChars());
else
- e->error("no property '%s' for type '%s'",
+ e->error("no property `%s` for type `%s`",
ident->toChars(), toChars());
return new ErrorExp();
const char *s = toChars();
e = new StringExp(loc, const_cast<char *>(s), strlen(s));
Scope sc;
- e = ::semantic(e, &sc);
+ e = expressionSemantic(e, &sc);
}
else if (ident == Id::_mangleof)
{
return this;
}
-Type *TypeStruct::semantic(Loc, Scope *sc)
-{
- //printf("TypeStruct::semantic('%s')\n", sym->toChars());
- if (deco)
- {
- if (sc && sc->cppmangle != CPPMANGLEdefault)
- {
- if (this->cppmangle == CPPMANGLEdefault)
- this->cppmangle = sc->cppmangle;
- else
- assert(this->cppmangle == sc->cppmangle);
- }
- return this;
- }
-
- /* Don't semantic for sym because it should be deferred until
- * sizeof needed or its members accessed.
- */
- // instead, parent should be set correctly
- assert(sym->parent);
-
- if (sym->type->ty == Terror)
- return Type::terror;
- if (sc)
- this->cppmangle = sc->cppmangle;
- return merge();
-}
-
d_uns64 TypeStruct::size(Loc loc)
{
return sym->size(loc);
/* Create a TupleExp out of the fields of the struct e:
* (e.field0, e.field1, e.field2, ...)
*/
- e = ::semantic(e, sc); // do this before turning on noaccesscheck
+ e = expressionSemantic(e, sc); // do this before turning on noaccesscheck
sym->size(e->loc); // do semantic of type
e = new TupleExp(e->loc, e0, exps);
Scope *sc2 = sc->push();
sc2->flags = sc->flags | SCOPEnoaccesscheck;
- e = ::semantic(e, sc2);
+ e = expressionSemantic(e, sc2);
sc2->pop();
return e;
}
(!v->type->deco && v->inuse))
{
if (v->inuse) // Bugzilla 9494
- e->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ e->error("circular reference to %s `%s`", v->kind(), v->toPrettyChars());
else
- e->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ e->error("forward reference to %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
if (v->type->ty == Terror)
{
if (v->inuse)
{
- e->error("circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ e->error("circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
checkAccess(e->loc, sc, NULL, v);
Expression *ve = new VarExp(e->loc, v);
- ve = ::semantic(ve, sc);
+ ve = expressionSemantic(ve, sc);
return ve;
}
}
if (Type *t = s->getType())
{
- return ::semantic(new TypeExp(e->loc, t), sc);
+ return expressionSemantic(new TypeExp(e->loc, t), sc);
}
TemplateMixin *tm = s->isTemplateMixin();
e = new TemplateExp(e->loc, td);
else
e = new DotTemplateExp(e->loc, e, td);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
{
if (!ti->semanticRun)
{
- ti->semantic(sc);
+ dsymbolSemantic(ti, sc);
if (!ti->inst || ti->errors) // if template failed to expand
return new ErrorExp();
}
e = new ScopeExp(e->loc, ti);
else
e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
- return ::semantic(e, sc);
+ return expressionSemantic(e, sc);
}
if (s->isImport() || s->isModule() || s->isPackage())
if (TupleDeclaration *tup = d->isTupleDeclaration())
{
e = new TupleExp(e->loc, tup);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (d->needThis() && sc->intypeof != 1)
if (hasThis(sc))
{
e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
}
if (d->semanticRun == PASSinit)
- d->semantic(NULL);
+ dsymbolSemantic(d, NULL);
checkAccess(e->loc, sc, e, d);
VarExp *ve = new VarExp(e->loc, d);
if (d->isVarDeclaration() && d->needThis())
checkAccess(e->loc, sc, e, d);
Expression *ve = new VarExp(e->loc, d);
e = unreal ? ve : new CommaExp(e->loc, e, ve);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
e = new DotVarExp(e->loc, e, d);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
Expression *e;
if (vd->inuse)
{
- error(loc, "circular reference to '%s'", vd->toPrettyChars());
+ error(loc, "circular reference to `%s`", vd->toPrettyChars());
return new ErrorExp();
}
if (vd->offset < offset || vd->type->size() == 0)
return this;
}
-Type *TypeClass::semantic(Loc, Scope *sc)
-{
- //printf("TypeClass::semantic(%s)\n", sym->toChars());
- if (deco)
- {
- if (sc && sc->cppmangle != CPPMANGLEdefault)
- {
- if (this->cppmangle == CPPMANGLEdefault)
- this->cppmangle = sc->cppmangle;
- else
- assert(this->cppmangle == sc->cppmangle);
- }
- return this;
- }
-
- /* Don't semantic for sym because it should be deferred until
- * sizeof needed or its members accessed.
- */
- // instead, parent should be set correctly
- assert(sym->parent);
-
- if (sym->type->ty == Terror)
- return Type::terror;
- if (sc)
- this->cppmangle = sc->cppmangle;
- return merge();
-}
-
d_uns64 TypeClass::size(Loc)
{
return target.ptrsize;
{
/* Create a TupleExp
*/
- e = ::semantic(e, sc); // do this before turning on noaccesscheck
+ e = expressionSemantic(e, sc); // do this before turning on noaccesscheck
sym->size(e->loc); // do semantic of type
e = new TupleExp(e->loc, e0, exps);
Scope *sc2 = sc->push();
sc2->flags = sc->flags | SCOPEnoaccesscheck;
- e = ::semantic(e, sc2);
+ e = expressionSemantic(e, sc2);
sc2->pop();
return e;
}
if (e->op == TOKtype)
return Type::getProperty(e->loc, ident, 0);
e = new DotTypeExp(e->loc, e, sym);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (ClassDeclaration *cbase = sym->searchBase(ident))
e = new CastExp(e->loc, e, ifbase->type);
else
e = new DotTypeExp(e->loc, e, cbase);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
*/
e = e->castTo(sc, tvoidptr->immutableOf()->pointerTo()->pointerTo());
e = new PtrExp(e->loc, e);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
e = e->castTo(sc, tvoidptr->pointerTo());
e = new AddExp(e->loc, e, new IntegerExp(1));
e = new PtrExp(e->loc, e);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (ident == Id::outer && sym->vthis)
{
if (sym->vthis->semanticRun == PASSinit)
- sym->vthis->semantic(NULL);
+ dsymbolSemantic(sym->vthis, NULL);
if (ClassDeclaration *cdp = sym->toParent2()->isClassDeclaration())
{
(!v->type->deco && v->inuse))
{
if (v->inuse) // Bugzilla 9494
- e->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ e->error("circular reference to %s `%s`", v->kind(), v->toPrettyChars());
else
- e->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ e->error("forward reference to %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
if (v->type->ty == Terror)
{
if (v->inuse)
{
- e->error("circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ e->error("circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
return new ErrorExp();
}
checkAccess(e->loc, sc, NULL, v);
Expression *ve = new VarExp(e->loc, v);
- ve = ::semantic(ve, sc);
+ ve = expressionSemantic(ve, sc);
return ve;
}
}
if (Type *t = s->getType())
{
- return ::semantic(new TypeExp(e->loc, t), sc);
+ return expressionSemantic(new TypeExp(e->loc, t), sc);
}
TemplateMixin *tm = s->isTemplateMixin();
e = new TemplateExp(e->loc, td);
else
e = new DotTemplateExp(e->loc, e, td);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
{
if (!ti->semanticRun)
{
- ti->semantic(sc);
+ dsymbolSemantic(ti, sc);
if (!ti->inst || ti->errors) // if template failed to expand
return new ErrorExp();
}
e = new ScopeExp(e->loc, ti);
else
e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
- return ::semantic(e, sc);
+ return expressionSemantic(e, sc);
}
if (s->isImport() || s->isModule() || s->isPackage())
if (TupleDeclaration *tup = d->isTupleDeclaration())
{
e = new TupleExp(e->loc, tup);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (d->needThis() && sc->intypeof != 1)
{
// This is almost same as getRightThis() in expression.c
Expression *e1 = new ThisExp(e->loc);
- e1 = ::semantic(e1, sc);
+ e1 = expressionSemantic(e1, sc);
L2:
Type *t = e1->type->toBasetype();
ClassDeclaration *cd = e->type->isClassHandle();
{
e = new DotTypeExp(e1->loc, e1, cd);
e = new DotVarExp(e->loc, e, d);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
if (tcd && tcd->isNested())
e1->type = tcd->vthis->type;
e1->type = e1->type->addMod(t->mod);
// Do not call checkNestedRef()
- //e1 = ::semantic(e1, sc);
+ //e1 = expressionSemantic(e1, sc);
// Skip up over nested functions, and get the enclosing
// class type.
{ e1->type = s->isClassDeclaration()->type;
e1->type = e1->type->addMod(t->mod);
if (n > 1)
- e1 = ::semantic(e1, sc);
+ e1 = expressionSemantic(e1, sc);
}
else
- e1 = ::semantic(e1, sc);
+ e1 = expressionSemantic(e1, sc);
goto L2;
}
}
}
//printf("e = %s, d = %s\n", e->toChars(), d->toChars());
if (d->semanticRun == PASSinit)
- d->semantic(NULL);
+ dsymbolSemantic(d, NULL);
checkAccess(e->loc, sc, e, d);
VarExp *ve = new VarExp(e->loc, d);
if (d->isVarDeclaration() && d->needThis())
checkAccess(e->loc, sc, e, d);
Expression *ve = new VarExp(e->loc, d);
e = unreal ? ve : new CommaExp(e->loc, e, ve);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
e = new DotVarExp(e->loc, e, d);
- e = ::semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
{
//printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to->toChars(), toChars(), cdto->isBaseInfoComplete(), sym->isBaseInfoComplete());
if (cdto->semanticRun < PASSsemanticdone && !cdto->isBaseInfoComplete())
- cdto->semantic(NULL);
+ dsymbolSemantic(cdto, NULL);
if (sym->semanticRun < PASSsemanticdone && !sym->isBaseInfoComplete())
- sym->semantic(NULL);
+ dsymbolSemantic(sym, NULL);
if (cdto->isBaseOf(sym, NULL) && MODimplicitConv(mod, to->mod))
{
//printf("'to' is base\n");
return t;
}
-Type *TypeTuple::semantic(Loc, Scope *)
-{
- //printf("TypeTuple::semantic(this = %p)\n", this);
- //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
- if (!deco)
- deco = merge()->deco;
-
- /* Don't return merge(), because a tuple with one type has the
- * same deco as that type.
- */
- return this;
-}
-
bool TypeTuple::equals(RootObject *o)
{
Type *t = (Type *)o;
}
else
{
- error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars());
+ error(loc, "no property `%s` for tuple `%s`", ident->toChars(), toChars());
e = new ErrorExp();
}
return e;
return t;
}
-Type *TypeSlice::semantic(Loc loc, Scope *sc)
-{
- //printf("TypeSlice::semantic() %s\n", toChars());
- Type *tn = next->semantic(loc, sc);
- //printf("next: %s\n", tn->toChars());
-
- Type *tbn = tn->toBasetype();
- if (tbn->ty != Ttuple)
- {
- error(loc, "can only slice tuple types, not %s", tbn->toChars());
- return Type::terror;
- }
- TypeTuple *tt = (TypeTuple *)tbn;
-
- lwr = semanticLength(sc, tbn, lwr);
- lwr = lwr->ctfeInterpret();
- uinteger_t i1 = lwr->toUInteger();
-
- upr = semanticLength(sc, tbn, upr);
- upr = upr->ctfeInterpret();
- uinteger_t i2 = upr->toUInteger();
-
- if (!(i1 <= i2 && i2 <= tt->arguments->length))
- {
- error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, tt->arguments->length);
- return Type::terror;
- }
-
- next = tn;
- transitive();
-
- Parameters *args = new Parameters;
- args->reserve((size_t)(i2 - i1));
- for (size_t i = (size_t)i1; i < (size_t)i2; i++)
- {
- Parameter *arg = (*tt->arguments)[i];
- args->push(arg);
- }
- Type *t = new TypeTuple(args);
- return t->semantic(loc, sc);
-}
-
void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
{
next->resolve(loc, sc, pe, pt, ps, intypeid);
sym->parent = sc->scopesym;
sc = sc->push(sym);
sc = sc->startCTFE();
- lwr = ::semantic(lwr, sc);
- upr = ::semantic(upr, sc);
+ lwr = expressionSemantic(lwr, sc);
+ upr = expressionSemantic(upr, sc);
sc = sc->endCTFE();
sc = sc->pop();
/* 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.
typedef struct TYPE type;
#endif
+Type *typeSemantic(Type *type, const Loc &loc, Scope *sc);
void semanticTypeInfo(Scope *sc, Type *t);
MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm = NULL, size_t inferStart = 0);
StorageClass ModToStc(unsigned mod);
d_uns64 size();
virtual d_uns64 size(Loc loc);
virtual unsigned alignsize();
- virtual Type *semantic(Loc loc, Scope *sc);
Type *trySemantic(Loc loc, Scope *sc);
Type *merge();
Type *merge2();
static TypeVector *create(Type *basetype);
const char *kind();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
d_uns64 size(Loc loc);
unsigned alignsize();
Expression *getProperty(Loc loc, Identifier *ident, int flag);
Type *syntaxCopy();
d_uns64 size(Loc loc);
unsigned alignsize();
- Type *semantic(Loc loc, Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
bool isString();
Type *syntaxCopy();
d_uns64 size(Loc loc) /*const*/;
unsigned alignsize() /*const*/;
- Type *semantic(Loc loc, Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
bool isString();
const char *kind();
Type *syntaxCopy();
d_uns64 size(Loc loc);
- Type *semantic(Loc loc, Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
Expression *defaultInit(Loc loc);
static TypePointer *create(Type *t);
const char *kind();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
d_uns64 size(Loc loc) /*const*/;
MATCH implicitConvTo(Type *to);
MATCH constConv(Type *to);
TypeReference(Type *t);
const char *kind();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
d_uns64 size(Loc loc) /*const*/;
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
Expression *defaultInit(Loc loc);
static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0);
const char *kind();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
void purityLevel();
bool hasLazyParameters();
bool isDstyleVariadic() const;
static TypeDelegate *create(Type *t);
const char *kind();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
Type *addStorageClass(StorageClass stc);
d_uns64 size(Loc loc) /*const*/;
unsigned alignsize() /*const*/;
TypeTraits(const Loc &loc, TraitsExp *exp);
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
d_uns64 size(Loc loc);
void accept(Visitor *v) { v->visit(this); }
Type *syntaxCopy();
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
Dsymbol *toDsymbol(Scope *sc);
- Type *semantic(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
const char *kind();
Type *syntaxCopy();
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- Type *semantic(Loc loc, Scope *sc);
Dsymbol *toDsymbol(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
Type *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- Type *semantic(Loc loc, Scope *sc);
d_uns64 size(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
Type *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- Type *semantic(Loc loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
d_uns64 size(Loc loc);
unsigned alignsize();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
Dsymbol *toDsymbol(Scope *sc);
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
structalign_t alignment();
Type *syntaxCopy();
d_uns64 size(Loc loc);
unsigned alignsize();
- Type *semantic(Loc loc, Scope *sc);
Dsymbol *toDsymbol(Scope *sc);
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
Expression *getProperty(Loc loc, Identifier *ident, int flag);
const char *kind();
d_uns64 size(Loc loc) /*const*/;
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
Dsymbol *toDsymbol(Scope *sc);
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
ClassDeclaration *isClassHandle();
TypeTuple(Type *t1, Type *t2);
const char *kind();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
bool equals(RootObject *o);
Expression *getProperty(Loc loc, Identifier *ident, int flag);
Expression *defaultInit(Loc loc);
TypeSlice(Type *next, Expression *lwr, Expression *upr);
const char *kind();
Type *syntaxCopy();
- Type *semantic(Loc loc, Scope *sc);
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
void accept(Visitor *v) { v->visit(this); }
};
/* 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.
if (f->setGC())
{
- e->error("array literal in @nogc %s '%s' may cause GC allocation",
+ e->error("array literal in @nogc %s `%s` may cause GC allocation",
f->kind(), f->toPrettyChars());
err = true;
return;
if (f->setGC())
{
- e->error("associative array literal in @nogc %s '%s' may cause GC allocation",
+ e->error("associative array literal in @nogc %s `%s` may cause GC allocation",
f->kind(), f->toPrettyChars());
err = true;
return;
if (f->setGC())
{
- e->error("cannot use 'new' in @nogc %s '%s'",
+ e->error("cannot use `new` in @nogc %s `%s`",
f->kind(), f->toPrettyChars());
err = true;
return;
}
- f->printGCUsage(e->loc, "'new' causes GC allocation");
+ f->printGCUsage(e->loc, "`new` causes GC allocation");
}
void visit(DeleteExp *e)
if (f->setGC())
{
- e->error("cannot use 'delete' in @nogc %s '%s'",
+ e->error("cannot use `delete` in @nogc %s `%s`",
f->kind(), f->toPrettyChars());
err = true;
return;
}
- f->printGCUsage(e->loc, "'delete' requires GC");
+ f->printGCUsage(e->loc, "`delete` requires GC");
}
void visit(IndexExp* e)
{
if (f->setGC())
{
- e->error("indexing an associative array in @nogc %s '%s' may cause GC allocation",
+ e->error("indexing an associative array in @nogc %s `%s` may cause GC allocation",
f->kind(), f->toPrettyChars());
err = true;
return;
{
if (f->setGC())
{
- e->error("setting 'length' in @nogc %s '%s' may cause GC allocation",
+ e->error("setting `length` in @nogc %s `%s` may cause GC allocation",
f->kind(), f->toPrettyChars());
err = true;
return;
}
- f->printGCUsage(e->loc, "setting 'length' may cause GC allocation");
+ f->printGCUsage(e->loc, "setting `length` may cause GC allocation");
}
}
{
if (f->setGC())
{
- e->error("cannot use operator ~= in @nogc %s '%s'",
+ e->error("cannot use operator ~= in @nogc %s `%s`",
f->kind(), f->toPrettyChars());
err = true;
return;
{
if (f->setGC())
{
- e->error("cannot use operator ~ in @nogc %s '%s'",
+ e->error("cannot use operator ~ in @nogc %s `%s`",
f->kind(), f->toPrettyChars());
err = true;
return;
// Compiler implementation of the D programming language
-// Copyright: Copyright (C) 2014-2020 by The D Language Foundation, All Rights Reserved
+// Copyright: Copyright (C) 2014-2021 by The D Language Foundation, All Rights Reserved
// Authors: Walter Bright, http://www.digitalmars.com
// License: http://boost.org/LICENSE_1_0.txt
// Source: https://github.com/D-Programming-Language/dmd/blob/master/src/nspace.c
}
}
-void Nspace::semantic(Scope *sc)
-{
- if (semanticRun != PASSinit)
- return;
- if (_scope)
- {
- sc = _scope;
- _scope = NULL;
- }
- if (!sc)
- return;
-
- semanticRun = PASSsemantic;
- parent = sc->parent;
- if (members)
- {
- assert(sc);
- sc = sc->push(this);
- sc->linkage = LINKcpp; // note that namespaces imply C++ linkage
- sc->parent = this;
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->importAll(sc);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic(sc);
- }
- sc->pop();
- }
- semanticRun = PASSsemanticdone;
-}
-
-void Nspace::semantic2(Scope *sc)
-{
- if (semanticRun >= PASSsemantic2)
- return;
- semanticRun = PASSsemantic2;
- if (members)
- {
- assert(sc);
- sc = sc->push(this);
- sc->linkage = LINKcpp;
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic2(sc);
- }
- sc->pop();
- }
-}
-
-void Nspace::semantic3(Scope *sc)
-{
- if (semanticRun >= PASSsemantic3)
- return;
- semanticRun = PASSsemantic3;
- if (members)
- {
- sc = sc->push(this);
- sc->linkage = LINKcpp;
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->semantic3(sc);
- }
- sc->pop();
- }
-}
-
const char *Nspace::kind() const
{
return "namespace";
{
//printf("%s::Nspace::search('%s')\n", toChars(), ident->toChars());
if (_scope && !symtab)
- semantic(_scope);
+ dsymbolSemantic(this, _scope);
if (!members || !symtab) // opaque or semantic() is not yet called
{
- error("is forward referenced when looking for '%s'", ident->toChars());
+ error("is forward referenced when looking for `%s`", ident->toChars());
return NULL;
}
{
//printf("Nspace::setFieldOffset() %s\n", toChars());
if (_scope) // if fwd reference
- semantic(NULL); // try to resolve it
+ dsymbolSemantic(this, NULL); // try to resolve it
if (members)
{
for (size_t i = 0; i < members->length; i++)
/* 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.
Dsymbol *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
- void semantic3(Scope *sc);
bool oneMember(Dsymbol **ps, Identifier *ident);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
int apply(Dsymbol_apply_ft_t fp, void *param);
/* Compiler implementation of the D programming language
- * Copyright (C) 2015-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2015-2021 by The D Language Foundation, All Rights Reserved
* written by Michel Fortin
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
/* Compiler implementation of the D programming language
- * Copyright (C) 2015-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2015-2021 by The D Language Foundation, All Rights Reserved
* written by Michel Fortin
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
/* 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.
static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags = 0);
Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id);
bool MODimplicitConv(MOD modfrom, MOD modto);
-Expression *trySemantic(Expression *e, Scope *sc);
-Expression *binSemanticProp(BinExp *e, Scope *sc);
-Expression *semantic(Expression *e, Scope *sc);
/******************************** Expression **************************/
default: break;
}
Expression *e = new StringExp(Loc(), const_cast<char *>(Token::toChars(op)));
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
Objects *tiargs = new Objects();
tiargs->push(e);
return tiargs;
if (e->e1->op == TOKarray)
{
ArrayExp *ae = (ArrayExp *)e->e1;
- ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = expressionSemantic(ae->e1, sc);
ae->e1 = resolveProperties(sc, ae->e1);
Expression *ae1old = ae->e1;
if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
result = trySemantic(result, sc);
else
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
if (result)
{
result = Expression::combine(e0, result);
Objects *tiargs = opToArg(sc, e->op);
result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceUnary, tiargs);
result = new CallExp(e->loc, result, a);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
result = Expression::combine(e0, result);
return;
}
ae->lengthVar = NULL;
}
- e->e1 = semantic(e->e1, sc);
+ e->e1 = expressionSemantic(e->e1, sc);
e->e1 = resolveProperties(sc, e->e1);
if (e->e1->op == TOKerror)
{
Objects *tiargs = opToArg(sc, e->op);
result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
result = new CallExp(e->loc, result);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
void visit(ArrayExp *ae)
{
//printf("ArrayExp::op_overload() (%s)\n", ae->toChars());
- ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = expressionSemantic(ae->e1, sc);
ae->e1 = resolveProperties(sc, ae->e1);
Expression *ae1old = ae->e1;
if (maybeSlice)
{
result = new SliceExp(ae->loc, ae->e1, ie);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
// Convert to IndexExp
if (ae->arguments->length == 1)
{
result = new IndexExp(ae->loc, ae->e1, (*ae->arguments)[0]);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
}
if (maybeSlice) // a[] might be: a.opSlice()
result = trySemantic(result, sc);
else
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
if (result)
{
result = Expression::combine(e0, result);
if (maybeSlice && ae->e1->op == TOKtype)
{
result = new SliceExp(ae->loc, ae->e1, ie);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
result = Expression::combine(e0, result);
return;
}
}
result = new DotIdExp(ae->loc, ae->e1, Id::slice);
result = new CallExp(ae->loc, result, a);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
result = Expression::combine(e0, result);
return;
}
tiargs->push(e->to);
result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
result = new CallExp(e->loc, result);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
if ((t1->ty == Tclass && e->e2->op == TOKnull) ||
(t2->ty == Tclass && e->e1->op == TOKnull))
{
- e->error("use '%s' instead of '%s' when comparing with null",
+ e->error("use `%s` instead of `%s` when comparing with null",
Token::toChars(e->op == TOKequal ? TOKidentity : TOKnotidentity),
Token::toChars(e->op));
result = new ErrorExp();
result = new CallExp(e->loc, result, e1x, e2x);
if (e->op == TOKnotequal)
result = new NotExp(e->loc, result);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
}
if (result->op == TOKcall && e->op == TOKnotequal)
{
result = new NotExp(result->loc, result);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
}
return;
}
*/
TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
result = new IdentityExp(op2, e->loc, e->e1, e->e2);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
// Use bitwise equality.
TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
result = new IdentityExp(op2, e->loc, e->e1, e->e2);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
e->att2 = t2;
e->e1 = new DotIdExp(e->loc, e->e1, Id::_tupleof);
e->e2 = new DotIdExp(e->loc, e->e2, Id::_tupleof);
- result = semantic(e, sc);
+ result = expressionSemantic(e, sc);
/* Bugzilla 15292, if the rewrite result is same with the original,
* the equality is unresolvable because it has recursive definition.
assert(result);
}
result = Expression::combine(Expression::combine(tup1->e0, tup2->e0), result);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
return;
}
}
if (e->e1->op == TOKarray)
{
ArrayExp *ae = (ArrayExp *)e->e1;
- ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = expressionSemantic(ae->e1, sc);
ae->e1 = resolveProperties(sc, ae->e1);
Expression *ae1old = ae->e1;
if (result->op == TOKerror)
return;
- result = semantic(e->e2, sc);
+ result = expressionSemantic(e->e2, sc);
if (result->op == TOKerror)
return;
e->e2 = result;
if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
result = trySemantic(result, sc);
else
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
if (result)
{
result = Expression::combine(e0, result);
if (result->op == TOKerror)
return;
- result = semantic(e->e2, sc);
+ result = expressionSemantic(e->e2, sc);
if (result->op == TOKerror)
return;
e->e2 = result;
Objects *tiargs = opToArg(sc, e->op);
result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceOpAssign, tiargs);
result = new CallExp(e->loc, result, a);
- result = semantic(result, sc);
+ result = expressionSemantic(result, sc);
result = Expression::combine(e0, result);
return;
}
e = new DotIdExp(loc, ethis, d->ident);
e = new CallExp(loc, e, earg);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
return e;
}
while (1)
{
- aggr = semantic(aggr, sc);
+ aggr = expressionSemantic(aggr, sc);
aggr = resolveProperties(sc, aggr);
aggr = aggr->optimize(WANTvalue);
if (!aggr->type || aggr->op == TOKerror)
Parameter *p = (*fes->parameters)[u];
if (p->type)
{
- p->type = p->type->semantic(fes->loc, sc);
+ p->type = typeSemantic(p->type, fes->loc, sc);
p->type = p->type->addStorageClass(p->storageClass);
}
}
/* 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
#include "ctfe.h"
#include "errors.h"
-Expression *semantic(Expression *e, Scope *sc);
-
/*************************************
* If variable has a const initializer,
* return that initializer.
if (!v)
return e;
if (!v->originalType && v->semanticRun < PASSsemanticdone) // semantic() not yet run
- v->semantic(NULL);
+ dsymbolSemantic(v, NULL);
if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest)
{
{
// const var initialized with non-const expression
ei = ei->implicitCastTo(NULL, v->type);
- ei = semantic(ei, NULL);
+ ei = expressionSemantic(ei, NULL);
}
else
goto L1;
/* 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.
}
default:
{
- error("'module' expected instead of %s", token.toChars());
+ error("`module` expected instead of %s", token.toChars());
nextToken();
break;
}
md->msg = msg;
if (token.value != TOKsemicolon)
- error("';' expected following module declaration instead of %s", token.toChars());
+ error("`;` expected following module declaration instead of %s", token.toChars());
nextToken();
addComment(mod, comment);
}
}
else
{
- error("invariant body expected, not '%s'", token.toChars());
+ error("invariant body expected, not `%s`", token.toChars());
goto Lerror;
}
break;
case TOKcolon:
case TOKlcurly:
- error("declaration expected, not '%s'",token.toChars());
+ error("declaration expected, not `%s`",token.toChars());
goto Lerror;
case TOKrcurly:
case TOKeof:
if (once)
- error("declaration expected, not '%s'", token.toChars());
+ error("declaration expected, not `%s`", token.toChars());
return decldefs;
case TOKstatic:
if (pAttrs->protection.kind != Prot::undefined)
{
if (pAttrs->protection.kind != prot)
- error("conflicting protection attribute '%s' and '%s'",
+ error("conflicting protection attribute `%s` and `%s`",
protectionToChars(pAttrs->protection.kind), protectionToChars(prot));
else
- error("redundant protection attribute '%s'", protectionToChars(prot));
+ error("redundant protection attribute `%s`", protectionToChars(prot));
}
pAttrs->protection.kind = prot;
continue;
default:
- error("declaration expected, not '%s'",token.toChars());
+ error("declaration expected, not `%s`",token.toChars());
Lerror:
while (token.value != TOKsemicolon && token.value != TOKeof)
nextToken();
OutBuffer buf;
stcToBuffer(&buf, stc);
if (deprec)
- deprecation("redundant attribute '%s'", buf.peekChars());
+ deprecation("redundant attribute `%s`", buf.peekChars());
else
- error("redundant attribute '%s'", buf.peekChars());
+ error("redundant attribute `%s`", buf.peekChars());
return storageClass | stc;
}
{
StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest);
if (u & (u - 1))
- error("conflicting attribute '%s'", Token::toChars(token.value));
+ error("conflicting attribute `%s`", Token::toChars(token.value));
}
if (stc & (STCgshared | STCshared | STCtls))
{
StorageClass u = storageClass & (STCgshared | STCshared | STCtls);
if (u & (u - 1))
- error("conflicting attribute '%s'", Token::toChars(token.value));
+ error("conflicting attribute `%s`", Token::toChars(token.value));
}
if (stc & (STCsafe | STCsystem | STCtrusted))
{
StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted);
if (u & (u - 1))
- error("conflicting attribute '@%s'", token.toChars());
+ error("conflicting attribute `@%s`", token.toChars());
}
return storageClass;
switch (token.value)
{
case TOKsemicolon:
- error("declaration expected following attribute, not ';'");
+ error("declaration expected following attribute, not `;`");
nextToken();
break;
if (token.value != TOKrcurly)
{
/* { */
- error("matching '}' expected, not %s", token.toChars());
+ error("matching `}` expected, not %s", token.toChars());
}
else
nextToken();
nextToken();
if (token.value != TOKidentifier)
{
- error("%s expected as dot-separated identifiers, got '%s'",
+ error("%s expected as dot-separated identifiers, got `%s`",
entity, token.toChars());
return NULL;
}
else if (StorageClass ss = stc & (STCshared | STCstatic)) // this()
{
if (ss == STCstatic)
- error(loc, "use 'static this()' to declare a static constructor");
+ error(loc, "use `static this()` to declare a static constructor");
else if (ss == (STCshared | STCstatic))
- error(loc, "use 'shared static this()' to declare a shared static constructor");
+ error(loc, "use `shared static this()` to declare a shared static constructor");
}
Expression *constraint = tpl ? parseConstraint() : NULL;
if (StorageClass ss = stc & (STCshared | STCstatic))
{
if (ss == STCstatic)
- error(loc, "use 'static ~this()' to declare a static destructor");
+ error(loc, "use `static ~this()` to declare a static destructor");
else if (ss == (STCshared | STCstatic))
- error(loc, "use 'shared static ~this()' to declare a shared static destructor");
+ error(loc, "use `shared static ~this()` to declare a shared static destructor");
}
DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor);
stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
if (stc & STCshared)
- error(loc, "use 'shared static this()' to declare a shared static constructor");
+ error(loc, "use `shared static this()` to declare a shared static constructor");
else if (stc & STCstatic)
appendStorageClass(stc, STCstatic); // complaint for the redundancy
else if (StorageClass modStc = stc & STC_TYPECTOR)
stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
if (stc & STCshared)
- error(loc, "use 'shared static ~this()' to declare a shared static destructor");
+ error(loc, "use `shared static ~this()` to declare a shared static destructor");
else if (stc & STCstatic)
appendStorageClass(stc, STCstatic); // complaint for the redundancy
else if (StorageClass modStc = stc & STC_TYPECTOR)
nextToken();
if (token.value != TOKidentifier)
{
- error("identifier expected following '.' instead of '%s'", token.toChars());
+ error("identifier expected following `.` instead of `%s`", token.toChars());
break;
}
loc = token.loc;
tm = new TemplateMixin(locMixin, id, tqual, tiargs);
if (token.value != TOKsemicolon)
- error("';' expected after mixin");
+ error("`;` expected after mixin");
nextToken();
return tm;
nextToken();
else
{
- error("';' expected");
+ error("`;` expected");
nextToken();
}
nextToken();
if (token.value != TOKidentifier)
{
- error("identifier expected following '.' instead of '%s'", token.toChars());
+ error("identifier expected following `.` instead of `%s`", token.toChars());
break;
}
if (maybeArray)
if (pident)
*pident = token.ident;
else
- error("unexpected identifer '%s' in declarator", token.ident->toChars());
+ error("unexpected identifer `%s` in declarator", token.ident->toChars());
ts = t;
nextToken();
break;
*/
if (isParameters(&peekt))
{
- error("function declaration without return type. (Note that constructors are always named 'this')");
+ error("function declaration without return type. (Note that constructors are always named `this`)");
}
else
error("unexpected ( in declarator");
if (init)
{
if (isThis)
- error("cannot use syntax 'alias this = %s', use 'alias %s this' instead",
+ error("cannot use syntax `alias this = %s`, use `alias %s this` instead",
init->toChars(), init->toChars());
else
error("alias cannot have initializer");
continue;
default:
- error("semicolon expected, not '%s'", token.toChars());
+ error("semicolon expected, not `%s`", token.toChars());
break;
}
}
continue;
default:
- error("semicolon expected following auto declaration, not '%s'", token.toChars());
+ error("semicolon expected following auto declaration, not `%s`", token.toChars());
break;
}
break;
case TOKcomma:
if (comma == 2)
- error("expression expected, not ','");
+ error("expression expected, not `,`");
nextToken();
comma = 2;
continue;
is->addInit(NULL, value);
comma = 1;
continue;
- //error("found '%s' instead of field initializer", token.toChars());
+ //error("found `%s` instead of field initializer", token.toChars());
//break;
}
break;
case TOKcomma:
if (comma == 2)
- error("expression expected, not ','");
+ error("expression expected, not `,`");
nextToken();
comma = 2;
continue;
break;
case TOKeof:
- error("found '%s' instead of array initializer", token.toChars());
+ error("found `%s` instead of array initializer", token.toChars());
break;
}
break;
const char *sp = !ident ? "" : " ";
const char *s = !ident ? "" : ident->toChars();
if (alt & 1) // contains C-style function pointer syntax
- error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t->toChars(), sp, s);
+ error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t->toChars(), sp, s);
else
- ::warning(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t->toChars(), sp, s);
+ ::warning(loc, "instead of C-style syntax, use D-style syntax `%s%s%s`", t->toChars(), sp, s);
}
nextToken();
//if (token.value == TOKsemicolon)
- //error("use '{ }' for an empty statement, not a ';'");
+ //error("use `{ }` for an empty statement, not a `;`");
Statements *statements = new Statements();
while (token.value != TOKrcurly && token.value != TOKeof)
{
if (!(flags & PSsemi_ok))
{
if (flags & PSsemi)
- deprecation("use '{ }' for an empty statement, not a ';'");
+ deprecation("use `{ }` for an empty statement, not a `;`");
else
- error("use '{ }' for an empty statement, not a ';'");
+ error("use `{ }` for an empty statement, not a `;`");
}
nextToken();
s = new ExpStatement(loc, (Expression *)NULL);
if (token.value == TOKsemicolon)
nextToken();
else
- error("terminating ';' required after do-while statement");
+ error("terminating `;` required after do-while statement");
s = new DoStatement(loc, body, condition, token.loc);
break;
}
if (toklist || label)
{
- error("asm statements must end in ';'");
+ error("asm statements must end in `;`");
}
break;
case TOKeof:
/* { */
- error("matching '}' expected, not end of file");
+ error("matching `}` expected, not end of file");
goto Lerror;
/* fall through */
}
default:
- error("found '%s' instead of statement", token.toChars());
+ error("found `%s` instead of statement", token.toChars());
goto Lerror;
Lerror:
void Parser::check(Loc loc, TOK value)
{
if (token.value != value)
- error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
+ error(loc, "found `%s` when expecting `%s`", token.toChars(), Token::toChars(value));
nextToken();
}
void Parser::check(TOK value, const char *string)
{
if (token.value != value)
- error("found '%s' when expecting '%s' following %s",
+ error("found `%s` when expecting `%s` following %s",
token.toChars(), Token::toChars(value), string);
nextToken();
}
case TOKdollar:
if (!inBrackets)
- error("'$' is valid only inside [] of index or slice");
+ error("`$` is valid only inside [] of index or slice");
e = new DollarExp(loc);
nextToken();
break;
{
if (token.postfix)
{ if (token.postfix != postfix)
- error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
+ error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
postfix = token.postfix;
}
}
check(TOKdot, t->toChars());
if (token.value != TOKidentifier)
- { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
+ { error("found `%s` when expecting identifier following `%s.`", token.toChars(), t->toChars());
goto Lerr;
}
e = typeDotIdExp(loc, t, token.ident);
e = parseAssignExp();
}
else if (keys)
- { error("'key:value' expected for associative array literal");
+ { error("`key:value` expected for associative array literal");
delete keys;
keys = NULL;
}
}
default:
- error("expression expected, not '%s'", token.toChars());
+ error("expression expected, not `%s`", token.toChars());
Lerr:
// Anything for e, as long as it's not NULL
e = new IntegerExp(loc, 0, Type::tint32);
continue;
}
else
- error("identifier expected following '.', not '%s'", token.toChars());
+ error("identifier expected following `.`, not `%s`", token.toChars());
break;
case TOKplusplus:
/* 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.
-/* Copyright (C) 2010-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 2010-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 2011-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2011-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.
-/* Copyright (C) 2011-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2011-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.
* to recognize them and generate equivalent and faster code.
*
* References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
- * Copyright: Copyright (C) 2014-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 2014-2021 by The D Language Foundation, All Rights Reserved
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Authors: Walter Bright
* Source: https://github.com/D-Programming-Language/dmd/blob/master/src/root/checkedint.c
/* Compiler implementation of the D programming language
- * Copyright (C) 2003-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2003-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.
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
-/* 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.
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
* Compiler implementation of the D programming language
* http://dlang.org
*
- * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* Authors: Martin Nowak, Walter Bright, http://www.digitalmars.com
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(DMDSRC root/_hash.h)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
-/* Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 2010-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 2010-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
-/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
/* 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.
/* 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.
/* 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.
--- /dev/null
+
+/* 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 "dsymbol.h"
+#include "aggregate.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "errors.h"
+#include "import.h"
+#include "init.h"
+#include "module.h"
+#include "nspace.h"
+#include "objc.h"
+#include "scope.h"
+#include "staticassert.h"
+#include "template.h"
+#include "visitor.h"
+
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
+void udaExpressionEval(Scope *sc, Expressions *exps);
+Objc *objc();
+
+class Semantic2Visitor : public Visitor
+{
+public:
+ Scope *sc;
+
+ Semantic2Visitor(Scope *sc)
+ {
+ this->sc = sc;
+ }
+
+ void visit(Dsymbol *)
+ {
+ // Most Dsymbols have no further semantic analysis needed
+ }
+
+ void visit(StaticAssert *sa)
+ {
+ //printf("StaticAssert::semantic2() %s\n", toChars());
+ ScopeDsymbol *sds = new ScopeDsymbol();
+ sc = sc->push(sds);
+ sc->tinst = NULL;
+ sc->minst = NULL;
+
+ bool errors = false;
+ bool result = evalStaticCondition(sc, sa->exp, sa->exp, errors);
+ sc = sc->pop();
+ if (errors)
+ {
+ errorSupplemental(sa->loc, "while evaluating: static assert(%s)", sa->exp->toChars());
+ }
+ else if (!result)
+ {
+ if (sa->msg)
+ {
+ sc = sc->startCTFE();
+ sa->msg = expressionSemantic(sa->msg, sc);
+ sa->msg = resolveProperties(sc, sa->msg);
+ sc = sc->endCTFE();
+ sa->msg = sa->msg->ctfeInterpret();
+ if (StringExp * se = sa->msg->toStringExp())
+ {
+ // same with pragma(msg)
+ se = se->toUTF8(sc);
+ sa->error("\"%.*s\"", (int)se->len, (char *)se->string);
+ }
+ else
+ sa->error("%s", sa->msg->toChars());
+ }
+ else
+ sa->error("(%s) is false", sa->exp->toChars());
+ if (sc->tinst)
+ sc->tinst->printInstantiationTrace();
+ if (!global.gag)
+ fatal();
+ }
+ }
+
+ void visit(TemplateInstance *tempinst)
+ {
+ if (tempinst->semanticRun >= PASSsemantic2)
+ return;
+ tempinst->semanticRun = PASSsemantic2;
+ if (!tempinst->errors && tempinst->members)
+ {
+ TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ sc = tempdecl->_scope;
+ assert(sc);
+ sc = sc->push(tempinst->argsym);
+ sc = sc->push(tempinst);
+ sc->tinst = tempinst;
+ sc->minst = tempinst->minst;
+
+ int needGagging = (tempinst->gagged && !global.gag);
+ unsigned int olderrors = global.errors;
+ int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+ if (needGagging)
+ oldGaggedErrors = global.startGagging();
+
+ for (size_t i = 0; i < tempinst->members->length; i++)
+ {
+ Dsymbol *s = (*tempinst->members)[i];
+ semantic2(s, sc);
+ if (tempinst->gagged && global.errors != olderrors)
+ break;
+ }
+
+ if (global.errors != olderrors)
+ {
+ if (!tempinst->errors)
+ {
+ if (!tempdecl->literal)
+ tempinst->error(tempinst->loc, "error instantiating");
+ if (tempinst->tinst)
+ tempinst->tinst->printInstantiationTrace();
+ }
+ tempinst->errors = true;
+ }
+ if (needGagging)
+ global.endGagging(oldGaggedErrors);
+
+ sc = sc->pop();
+ sc->pop();
+ }
+ }
+
+ void visit(TemplateMixin *tmix)
+ {
+ if (tmix->semanticRun >= PASSsemantic2)
+ return;
+ tmix->semanticRun = PASSsemantic2;
+ if (tmix->members)
+ {
+ assert(sc);
+ sc = sc->push(tmix->argsym);
+ sc = sc->push(tmix);
+ for (size_t i = 0; i < tmix->members->length; i++)
+ {
+ Dsymbol *s = (*tmix->members)[i];
+ semantic2(s, sc);
+ }
+ sc = sc->pop();
+ sc->pop();
+ }
+ }
+
+ void visit(VarDeclaration *vd)
+ {
+ if (vd->semanticRun < PASSsemanticdone && vd->inuse)
+ return;
+
+ //printf("VarDeclaration::semantic2('%s')\n", toChars());
+
+ if (vd->_init && !vd->toParent()->isFuncDeclaration())
+ {
+ vd->inuse++;
+ // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
+ vd->_init = initializerSemantic(vd->_init, sc, vd->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
+ vd->inuse--;
+ }
+ if (vd->_init && (vd->storage_class & STCmanifest))
+ {
+ /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
+ * Scan initializer looking for them. Issue error if found.
+ */
+ if (ExpInitializer *ei = vd->_init->isExpInitializer())
+ {
+ struct EnumInitializer
+ {
+ static bool arrayHasInvalidEnumInitializer(Expressions *elems)
+ {
+ for (size_t i = 0; i < elems->length; i++)
+ {
+ Expression *e = (*elems)[i];
+ if (e && hasInvalidEnumInitializer(e))
+ return true;
+ }
+ return false;
+ }
+
+ static bool hasInvalidEnumInitializer(Expression *e)
+ {
+ if (e->op == TOKclassreference)
+ return true;
+ if (e->op == TOKaddress && ((AddrExp *)e)->e1->op == TOKstructliteral)
+ return true;
+ if (e->op == TOKarrayliteral)
+ return arrayHasInvalidEnumInitializer(((ArrayLiteralExp *)e)->elements);
+ if (e->op == TOKstructliteral)
+ return arrayHasInvalidEnumInitializer(((StructLiteralExp *)e)->elements);
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+ return arrayHasInvalidEnumInitializer(ae->values) ||
+ arrayHasInvalidEnumInitializer(ae->keys);
+ }
+ return false;
+ }
+ };
+ if (EnumInitializer::hasInvalidEnumInitializer(ei->exp))
+ vd->error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
+ }
+ }
+ else if (vd->_init && vd->isThreadlocal())
+ {
+ if ((vd->type->ty == Tclass) && vd->type->isMutable() && !vd->type->isShared())
+ {
+ ExpInitializer *ei = vd->_init->isExpInitializer();
+ if (ei && ei->exp->op == TOKclassreference)
+ vd->error("is mutable. Only const or immutable class thread local variable are allowed, not %s", vd->type->toChars());
+ }
+ else if (vd->type->ty == Tpointer && vd->type->nextOf()->ty == Tstruct && vd->type->nextOf()->isMutable() && !vd->type->nextOf()->isShared())
+ {
+ ExpInitializer *ei = vd->_init->isExpInitializer();
+ if (ei && ei->exp->op == TOKaddress && ((AddrExp *)ei->exp)->e1->op == TOKstructliteral)
+ {
+ vd->error("is a pointer to mutable struct. Only pointers to const, immutable or shared struct thread local variable are allowed, not %s", vd->type->toChars());
+ }
+ }
+ }
+ vd->semanticRun = PASSsemantic2done;
+ }
+
+ void visit(Module *mod)
+ {
+ //printf("Module::semantic2('%s'): parent = %p\n", toChars(), mod->parent);
+ if (mod->semanticRun != PASSsemanticdone) // semantic() not completed yet - could be recursive call
+ return;
+ mod->semanticRun = PASSsemantic2;
+
+ // 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 = Scope::createGlobal(mod); // create root scope
+ //printf("Module = %p\n", sc.scopesym);
+
+ // Pass 2 semantic routines: do initializers and function bodies
+ for (size_t i = 0; i < mod->members->length; i++)
+ {
+ Dsymbol *s = (*mod->members)[i];
+ semantic2(s, sc);
+ }
+
+ if (mod->userAttribDecl)
+ {
+ semantic2(mod->userAttribDecl, sc);
+ }
+
+ sc = sc->pop();
+ sc->pop();
+ mod->semanticRun = PASSsemantic2done;
+ //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), mod->parent);
+ }
+
+ void visit(FuncDeclaration *fd)
+ {
+ if (fd->semanticRun >= PASSsemantic2done)
+ return;
+ assert(fd->semanticRun <= PASSsemantic2);
+ fd->semanticRun = PASSsemantic2;
+
+ objc()->setSelector(fd, sc);
+ objc()->validateSelector(fd);
+
+ if (fd->parent->isClassDeclaration())
+ {
+ objc()->checkLinkage(fd);
+ }
+ if (!fd->type || fd->type->ty != Tfunction)
+ return;
+ TypeFunction *f = fd->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)
+ semantic2(param->userAttribDecl, sc);
+ }
+ }
+
+ void visit(Import *i)
+ {
+ //printf("Import::semantic2('%s')\n", toChars());
+ if (i->mod)
+ {
+ semantic2(i->mod, NULL);
+ if (i->mod->needmoduleinfo)
+ {
+ //printf("module5 %s because of %s\n", sc->_module->toChars(), i->mod->toChars());
+ if (sc)
+ sc->_module->needmoduleinfo = 1;
+ }
+ }
+ }
+
+ void visit(Nspace *ns)
+ {
+ if (ns->semanticRun >= PASSsemantic2)
+ return;
+ ns->semanticRun = PASSsemantic2;
+ if (ns->members)
+ {
+ assert(sc);
+ sc = sc->push(ns);
+ sc->linkage = LINKcpp;
+ for (size_t i = 0; i < ns->members->length; i++)
+ {
+ Dsymbol *s = (*ns->members)[i];
+ semantic2(s, sc);
+ }
+ sc->pop();
+ }
+ }
+
+ void visit(AttribDeclaration *ad)
+ {
+ Dsymbols *d = ad->include(sc);
+
+ if (d)
+ {
+ Scope *sc2 = ad->newScope(sc);
+
+ for (size_t i = 0; i < d->length; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ semantic2(s, sc2);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+ }
+
+ /**
+ * Run the DeprecatedDeclaration's semantic2 phase then its members.
+ *
+ * The message set via a `DeprecatedDeclaration` can be either of:
+ * - a string literal
+ * - an enum
+ * - a static immutable
+ * So we need to call ctfe to resolve it.
+ * Afterward forwards to the members' semantic2.
+ */
+ void visit(DeprecatedDeclaration *dd)
+ {
+ dd->getMessage();
+ visit((AttribDeclaration *)dd);
+ }
+
+ void visit(AlignDeclaration *ad)
+ {
+ ad->getAlignment(sc);
+ visit((AttribDeclaration *)ad);
+ }
+
+ void visit(UserAttributeDeclaration *uad)
+ {
+ if (uad->decl && uad->atts && uad->atts->length && uad->_scope)
+ {
+ uad->_scope = NULL;
+ udaExpressionEval(sc, uad->atts);
+ }
+ visit((AttribDeclaration *)uad);
+ }
+
+ void visit(AggregateDeclaration *ad)
+ {
+ //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), ad->type->toChars(), ad->errors);
+ if (!ad->members)
+ return;
+
+ if (ad->_scope)
+ {
+ ad->error("has forward references");
+ return;
+ }
+
+ Scope *sc2 = ad->newScope(sc);
+
+ ad->determineSize(ad->loc);
+
+ for (size_t i = 0; i < ad->members->length; i++)
+ {
+ Dsymbol *s = (*ad->members)[i];
+ //printf("\t[%d] %s\n", i, s->toChars());
+ semantic2(s, sc2);
+ }
+
+ sc2->pop();
+ }
+};
+
+/*************************************
+ * Does semantic analysis on initializers and members of aggregates.
+ */
+void semantic2(Dsymbol *dsym, Scope *sc)
+{
+ Semantic2Visitor v(sc);
+ dsym->accept(&v);
+}
--- /dev/null
+
+/* 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 "dsymbol.h"
+#include "aggregate.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "errors.h"
+#include "id.h"
+#include "init.h"
+#include "module.h"
+#include "nspace.h"
+#include "scope.h"
+#include "statement.h"
+#include "statement_rewrite_walker.h"
+#include "target.h"
+#include "template.h"
+#include "visitor.h"
+
+bool allowsContractWithoutBody(FuncDeclaration *funcdecl);
+int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
+bool checkReturnEscape(Scope *sc, Expression *e, bool gag);
+bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag);
+TypeIdentifier *getThrowable();
+char *MODtoChars(MOD mod);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+void allocFieldinit(Scope *sc, size_t dim);
+void freeFieldinit(Scope *sc);
+
+/* 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()));
+}
+
+/********************************************************
+ * Generate Expression to call the invariant.
+ * Input:
+ * ad aggregate with the invariant
+ * vthis variable with 'this'
+ * Returns:
+ * void expression that calls the invariant
+ */
+static 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);
+ //dsymbolSemantic(e, 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;
+}
+
+/* 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;
+ catchSemantic(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);
+ }
+};
+
+class Semantic3Visitor : public Visitor
+{
+public:
+ Scope *sc;
+
+ Semantic3Visitor(Scope *sc)
+ {
+ this->sc = sc;
+ }
+
+ void visit(Dsymbol *)
+ {
+ // Most Dsymbols have no further semantic analysis needed
+ }
+
+ void visit(TemplateInstance *tempinst)
+ {
+ //if (tempinst->toChars()[0] == 'D') *(char*)0=0;
+ if (tempinst->semanticRun >= PASSsemantic3)
+ return;
+ tempinst->semanticRun = PASSsemantic3;
+ if (!tempinst->errors && tempinst->members)
+ {
+ TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ sc = tempdecl->_scope;
+ sc = sc->push(tempinst->argsym);
+ sc = sc->push(tempinst);
+ sc->tinst = tempinst;
+ sc->minst = tempinst->minst;
+
+ int needGagging = (tempinst->gagged && !global.gag);
+ unsigned int olderrors = global.errors;
+ int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+ /* If this is a gagged instantiation, gag errors.
+ * Future optimisation: If the results are actually needed, errors
+ * would already be gagged, so we don't really need to run semantic
+ * on the members.
+ */
+ if (needGagging)
+ oldGaggedErrors = global.startGagging();
+
+ for (size_t i = 0; i < tempinst->members->length; i++)
+ {
+ Dsymbol *s = (*tempinst->members)[i];
+ semantic3(s, sc);
+ if (tempinst->gagged && global.errors != olderrors)
+ break;
+ }
+
+ if (global.errors != olderrors)
+ {
+ if (!tempinst->errors)
+ {
+ if (!tempdecl->literal)
+ tempinst->error(tempinst->loc, "error instantiating");
+ if (tempinst->tinst)
+ tempinst->tinst->printInstantiationTrace();
+ }
+ tempinst->errors = true;
+ }
+ if (needGagging)
+ global.endGagging(oldGaggedErrors);
+
+ sc = sc->pop();
+ sc->pop();
+ }
+ }
+
+ void visit(TemplateMixin *tmix)
+ {
+ if (tmix->semanticRun >= PASSsemantic3)
+ return;
+ tmix->semanticRun = PASSsemantic3;
+ if (tmix->members)
+ {
+ sc = sc->push(tmix->argsym);
+ sc = sc->push(tmix);
+ for (size_t i = 0; i < tmix->members->length; i++)
+ {
+ Dsymbol *s = (*tmix->members)[i];
+ semantic3(s, sc);
+ }
+ sc = sc->pop();
+ sc->pop();
+ }
+ }
+
+ void visit(Module *mod)
+ {
+ //printf("Module::semantic3('%s'): parent = %p\n", mod->toChars(), mod->parent);
+ if (mod->semanticRun != PASSsemantic2done)
+ return;
+ mod->semanticRun = PASSsemantic3;
+
+ // 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 = Scope::createGlobal(mod); // create root scope
+ //printf("Module = %p\n", sc.scopesym);
+
+ // Pass 3 semantic routines: do initializers and function bodies
+ for (size_t i = 0; i < mod->members->length; i++)
+ {
+ Dsymbol *s = (*mod->members)[i];
+ //printf("Module %s: %s.semantic3()\n", mod->toChars(), s->toChars());
+ semantic3(s, sc);
+
+ mod->runDeferredSemantic2();
+ }
+
+ if (mod->userAttribDecl)
+ {
+ semantic3(mod->userAttribDecl, sc);
+ }
+
+ sc = sc->pop();
+ sc->pop();
+ mod->semanticRun = PASSsemantic3done;
+ }
+
+ void visit(FuncDeclaration *funcdecl)
+ {
+ VarDeclaration *_arguments = NULL;
+
+ if (!funcdecl->parent)
+ {
+ if (global.errors)
+ return;
+ //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", funcdecl->kind(), funcdecl->toChars(), sc);
+ assert(0);
+ }
+ if (funcdecl->errors || isError(funcdecl->parent))
+ {
+ funcdecl->errors = true;
+ return;
+ }
+ //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", funcdecl->parent->toChars(), funcdecl->toChars(), funcdecl, sc, funcdecl->loc.toChars());
+ //fflush(stdout);
+ //printf("storage class = x%x %x\n", sc->stc, funcdecl->storage_class);
+ //{ static int x; if (++x == 2) *(char*)0=0; }
+ //printf("\tlinkage = %d\n", sc->linkage);
+
+ if (funcdecl->ident == Id::assign && !funcdecl->inuse)
+ {
+ if (funcdecl->storage_class & STCinference)
+ {
+ /* Bugzilla 15044: For generated opAssign function, any errors
+ * from its body need to be gagged.
+ */
+ unsigned oldErrors = global.startGagging();
+ funcdecl->inuse++;
+ semantic3(funcdecl, sc);
+ funcdecl->inuse--;
+ if (global.endGagging(oldErrors)) // if errors happened
+ {
+ // Disable generated opAssign, because some members forbid identity assignment.
+ funcdecl->storage_class |= STCdisable;
+ funcdecl->fbody = NULL; // remove fbody which contains the error
+ funcdecl->semantic3Errors = false;
+ }
+ return;
+ }
+ }
+
+ //printf(" sc->incontract = %d\n", (sc->flags & SCOPEcontract));
+ if (funcdecl->semanticRun >= PASSsemantic3)
+ return;
+ funcdecl->semanticRun = PASSsemantic3;
+ funcdecl->semantic3Errors = false;
+
+ if (!funcdecl->type || funcdecl->type->ty != Tfunction)
+ return;
+ TypeFunction *f = (TypeFunction *)funcdecl->type;
+ if (!funcdecl->inferRetType && f->next->ty == Terror)
+ return;
+
+ if (!funcdecl->fbody && funcdecl->inferRetType && !f->next)
+ {
+ funcdecl->error("has no function body with return type inference");
+ return;
+ }
+
+ unsigned oldErrors = global.errors;
+
+ if (funcdecl->frequires)
+ {
+ for (size_t i = 0; i < funcdecl->foverrides.length; i++)
+ {
+ FuncDeclaration *fdv = funcdecl->foverrides[i];
+
+ if (fdv->fbody && !fdv->frequires)
+ {
+ funcdecl->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 = FuncDeclaration::needsFensure(funcdecl);
+
+ if (funcdecl->fbody || funcdecl->frequires || needEnsure)
+ {
+ /* Symbol table into which we place parameters and nested functions,
+ * solely to diagnose name collisions.
+ */
+ funcdecl->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 = funcdecl->loc;
+ ss->endlinnum = funcdecl->endloc.linnum;
+ Scope *sc2 = sc->push(ss);
+ sc2->func = funcdecl;
+ sc2->parent = funcdecl;
+ sc2->callSuper = 0;
+ sc2->sbreak = NULL;
+ sc2->scontinue = NULL;
+ sc2->sw = NULL;
+ sc2->fes = funcdecl->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 (funcdecl->ident != Id::require && funcdecl->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 = funcdecl->isFuncLiteralDeclaration())
+ {
+ if (AggregateDeclaration *ad = funcdecl->isMember2())
+ {
+ if (!sc->intypeof)
+ {
+ if (fld->tok == TOKdelegate)
+ funcdecl->error("cannot be %s members", ad->kind());
+ else
+ fld->tok = TOKfunction;
+ }
+ else
+ {
+ if (fld->tok != TOKfunction)
+ fld->tok = TOKdelegate;
+ }
+ }
+ }
+
+ // Declare 'this'
+ AggregateDeclaration *ad = funcdecl->isThis();
+ funcdecl->vthis = funcdecl->declareThis(sc2, ad);
+ //printf("[%s] ad = %p vthis = %p\n", funcdecl->loc.toChars(), ad, funcdecl->vthis);
+ //if (funcdecl->vthis) printf("\tvthis->type = %s\n", funcdecl->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)
+ funcdecl->error("D-style variadic functions cannot be used with -betterC");
+ else if (!Type::typeinfotypelist)
+ funcdecl->error("`object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions");
+ else
+ funcdecl->error("`object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions");
+ fatal();
+ }
+
+ // Declare _arguments[]
+ funcdecl->v_arguments = new VarDeclaration(Loc(), Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL);
+ funcdecl->v_arguments->storage_class |= STCtemp | STCparameter;
+ dsymbolSemantic(funcdecl->v_arguments, sc2);
+ sc2->insert(funcdecl->v_arguments);
+ funcdecl->v_arguments->parent = funcdecl;
+
+ //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;
+ dsymbolSemantic(_arguments, sc2);
+ sc2->insert(_arguments);
+ _arguments->parent = funcdecl;
+ }
+ if (f->linkage == LINKd || f->parameterList.length())
+ {
+ // Declare _argptr
+ Type *t = target.va_listType(funcdecl->loc, sc);
+ funcdecl->v_argptr = new VarDeclaration(Loc(), t, Id::_argptr, NULL);
+ funcdecl->v_argptr->storage_class |= STCtemp;
+ dsymbolSemantic(funcdecl->v_argptr, sc2);
+ sc2->insert(funcdecl->v_argptr);
+ funcdecl->v_argptr->parent = funcdecl;
+ }
+ }
+
+ /* 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
+ */
+ funcdecl->parameters = new VarDeclarations();
+ funcdecl->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(funcdecl->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 (funcdecl->flags & FUNCFLAGinferScope && !(fparam->storageClass & STCscope))
+ stc |= STCmaybescope;
+ stc |= fparam->storageClass & (STCin | STCout | STCref | STCreturn | STCscope | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
+ v->storage_class = stc;
+ dsymbolSemantic(v, sc2);
+ if (!sc2->insert(v))
+ funcdecl->error("parameter %s.%s is already defined", funcdecl->toChars(), v->toChars());
+ else
+ funcdecl->parameters->push(v);
+ funcdecl->localsymtab->insert(v);
+ v->parent = funcdecl;
+ 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(funcdecl->loc, fparam->ident, exps);
+ //printf("declaring tuple %s\n", v->toChars());
+ v->isexp = true;
+ if (!sc2->insert(v))
+ funcdecl->error("parameter %s.%s is already defined", funcdecl->toChars(), v->toChars());
+ funcdecl->localsymtab->insert(v);
+ v->parent = funcdecl;
+ }
+ }
+ }
+
+ // Precondition invariant
+ Statement *fpreinv = NULL;
+ if (funcdecl->addPreInvariant())
+ {
+ Expression *e = addInvariant(ad, funcdecl->vthis);
+ if (e)
+ fpreinv = new ExpStatement(Loc(), e);
+ }
+
+ // Postcondition invariant
+ Statement *fpostinv = NULL;
+ if (funcdecl->addPostInvariant())
+ {
+ Expression *e = addInvariant(ad, funcdecl->vthis);
+ if (e)
+ fpostinv = new ExpStatement(Loc(), e);
+ }
+
+ // Pre/Postcondition contract
+ if (!funcdecl->fbody)
+ funcdecl->buildEnsureRequire();
+
+ Scope *scout = NULL;
+ if (needEnsure || funcdecl->addPostInvariant())
+ {
+ if ((needEnsure && global.params.useOut == CHECKENABLEon) || fpostinv)
+ {
+ funcdecl->returnLabel = new LabelDsymbol(Id::returnLabel);
+ }
+
+ // scope of out contract (need for vresult->semantic)
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc2->scopesym;
+ sym->loc = funcdecl->loc;
+ sym->endlinnum = funcdecl->endloc.linnum;
+ scout = sc2->push(sym);
+ }
+
+ if (funcdecl->fbody)
+ {
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc2->scopesym;
+ sym->loc = funcdecl->loc;
+ sym->endlinnum = funcdecl->endloc.linnum;
+ sc2 = sc2->push(sym);
+
+ AggregateDeclaration *ad2 = funcdecl->isMember2();
+
+ /* If this is a class constructor
+ */
+ if (ad2 && funcdecl->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 && (funcdecl->storage_class & STCauto));
+
+ funcdecl->fbody = statementSemantic(funcdecl->fbody, sc2);
+ if (!funcdecl->fbody)
+ funcdecl->fbody = new CompoundStatement(Loc(), new Statements());
+
+ if (funcdecl->naked)
+ {
+ fpreinv = NULL; // can't accommodate with no stack frame
+ fpostinv = NULL;
+ }
+
+ assert(funcdecl->type == f ||
+ (funcdecl->type->ty == Tfunction &&
+ f->purity == PUREimpure &&
+ ((TypeFunction *)funcdecl->type)->purity >= PUREfwdref));
+ f = (TypeFunction *)funcdecl->type;
+
+ if (funcdecl->inferRetType)
+ {
+ // If no return type inferred yet, then infer a void
+ if (!f->next)
+ f->next = Type::tvoid;
+ if (f->checkRetType(funcdecl->loc))
+ funcdecl->fbody = new ErrorStatement();
+ }
+ if (global.params.vcomplex && f->next != NULL)
+ f->next->checkComplexTransition(funcdecl->loc);
+
+ if (funcdecl->returns && !funcdecl->fbody->isErrorStatement())
+ {
+ for (size_t i = 0; i < funcdecl->returns->length; )
+ {
+ Expression *exp = (*funcdecl->returns)[i]->exp;
+ if (exp->op == TOKvar && ((VarExp *)exp)->var == funcdecl->vresult)
+ {
+ if (addReturn0(funcdecl))
+ exp->type = Type::tint32;
+ else
+ exp->type = f->next;
+ // Remove `return vresult;` from returns
+ funcdecl->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 (funcdecl->storage_class & STCauto)
+ funcdecl->storage_class &= ~STCauto;
+ }
+ if (!target.isReturnOnStack(f, funcdecl->needThis()) || !funcdecl->checkNRVO())
+ funcdecl->nrvo_can = 0;
+
+ if (funcdecl->fbody->isErrorStatement())
+ ;
+ else if (funcdecl->isStaticCtorDeclaration())
+ {
+ /* It's a static constructor. Ensure that all
+ * ctor consts were initialized.
+ */
+ ScopeDsymbol *pd = funcdecl->toParent()->isScopeDsymbol();
+ for (size_t i = 0; i < pd->members->length; i++)
+ {
+ Dsymbol *s = (*pd->members)[i];
+ s->checkCtorConstInit();
+ }
+ }
+ else if (ad2 && funcdecl->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)
+ funcdecl->error("missing initializer for %s field %s", MODtoChars(v->type->mod), v->toChars());
+ else if (v->storage_class & STCnodefaultctor)
+ error(funcdecl->loc, "field %s must be initialized in constructor", v->toChars());
+ else if (v->type->needsNested())
+ error(funcdecl->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))
+ {
+ funcdecl->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, funcdecl->vthis->type, NULL, 1);
+ if (!fd)
+ {
+ funcdecl->error("no match for implicit super() call in constructor");
+ }
+ else if (fd->storage_class & STCdisable)
+ {
+ funcdecl->error("cannot call super() implicitly because it is annotated with @disable");
+ }
+ else
+ {
+ Expression *e1 = new SuperExp(Loc());
+ Expression *e = new CallExp(Loc(), e1);
+ e = expressionSemantic(e, sc2);
+
+ Statement *s = new ExpStatement(Loc(), e);
+ funcdecl->fbody = new CompoundStatement(Loc(), s, funcdecl->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.
+ */
+ funcdecl->buildEnsureRequire();
+
+ int blockexit = BEnone;
+ if (!funcdecl->fbody->isErrorStatement())
+ {
+ // Check for errors related to 'nothrow'.
+ unsigned int nothrowErrors = global.errors;
+ blockexit = blockExit(funcdecl->fbody, funcdecl, f->isnothrow);
+ if (f->isnothrow && (global.errors != nothrowErrors))
+ error(funcdecl->loc, "nothrow %s `%s` may throw", funcdecl->kind(), funcdecl->toPrettyChars());
+ if (funcdecl->flags & FUNCFLAGnothrowInprocess)
+ {
+ if (funcdecl->type == f) f = (TypeFunction *)f->copy();
+ f->isnothrow = !(blockexit & BEthrow);
+ }
+ }
+
+ if (funcdecl->fbody->isErrorStatement())
+ ;
+ else if (ad2 && funcdecl->isCtorDeclaration())
+ {
+ /* Append:
+ * return this;
+ * to function body
+ */
+ if (blockexit & BEfallthru)
+ {
+ Statement *s = new ReturnStatement(funcdecl->loc, NULL);
+ s = statementSemantic(s, sc2);
+ funcdecl->fbody = new CompoundStatement(funcdecl->loc, funcdecl->fbody, s);
+ funcdecl->hasReturnExp |= (funcdecl->hasReturnExp & 1 ? 16 : 1);
+ }
+ }
+ else if (funcdecl->fes)
+ {
+ // For foreach(){} body, append a return 0;
+ if (blockexit & BEfallthru)
+ {
+ Expression *e = new IntegerExp(0);
+ Statement *s = new ReturnStatement(Loc(), e);
+ funcdecl->fbody = new CompoundStatement(Loc(), funcdecl->fbody, s);
+ funcdecl->hasReturnExp |= (funcdecl->hasReturnExp & 1 ? 16 : 1);
+ }
+ assert(!funcdecl->returnLabel);
+ }
+ else
+ {
+ const bool inlineAsm = (funcdecl->hasReturnExp & 8) != 0;
+ if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
+ {
+ Expression *e;
+ if (!funcdecl->hasReturnExp)
+ funcdecl->error("has no return statement, but is expected to return a value of type %s", f->next->toChars());
+ else
+ funcdecl->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(funcdecl->endloc,
+ new IntegerExp(0),
+ new StringExp(funcdecl->loc, const_cast<char *>("missing return expression")));
+ }
+ else
+ e = new HaltExp(funcdecl->endloc);
+ e = new CommaExp(Loc(), e, f->next->defaultInit());
+ e = expressionSemantic(e, sc2);
+ Statement *s = new ExpStatement(Loc(), e);
+ funcdecl->fbody = new CompoundStatement(Loc(), funcdecl->fbody, s);
+ }
+ }
+
+ if (funcdecl->returns)
+ {
+ bool implicit0 = addReturn0(funcdecl);
+ Type *tret = implicit0 ? Type::tint32 : f->next;
+ assert(tret->ty != Tvoid);
+ if (funcdecl->vresult || funcdecl->returnLabel)
+ funcdecl->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 < funcdecl->returns->length; i++)
+ {
+ ReturnStatement *rs = (*funcdecl->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) &&
+ funcdecl->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 (!funcdecl->nrvo_can)
+ exp = doCopyOrMove(sc2, exp);
+
+ if (tret->hasPointers())
+ checkReturnEscape(sc2, exp, false);
+ }
+
+ exp = checkGC(sc2, exp);
+
+ if (funcdecl->vresult)
+ {
+ // Create: return vresult = exp;
+ exp = new BlitExp(rs->loc, funcdecl->vresult, exp);
+ exp->type = funcdecl->vresult->type;
+
+ if (rs->caseDim)
+ exp = Expression::combine(exp, new IntegerExp(rs->caseDim));
+ }
+ else if (funcdecl->tintro && !tret->equals(funcdecl->tintro->nextOf()))
+ {
+ exp = exp->implicitCastTo(sc2, funcdecl->tintro->nextOf());
+ }
+ rs->exp = exp;
+ }
+ }
+ if (funcdecl->nrvo_var || funcdecl->returnLabel)
+ {
+ NrvoWalker nw;
+ nw.fd = funcdecl;
+ nw.sc = sc2;
+ nw.visitStmt(funcdecl->fbody);
+ }
+
+ sc2 = sc2->pop();
+ }
+
+ funcdecl->frequire = funcdecl->mergeFrequire(funcdecl->frequire);
+ funcdecl->fensure = funcdecl->mergeFensure(funcdecl->fensure, Id::result);
+
+ Statement *freq = funcdecl->frequire;
+ Statement *fens = funcdecl->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 = funcdecl->loc;
+ sym->endlinnum = funcdecl->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 = statementSemantic(freq, sc2);
+ blockExit(freq, funcdecl, 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 && funcdecl->fensures)
+ {
+ for (size_t i = 0; i < funcdecl->fensures->length; i++)
+ {
+ Ensure e = (*funcdecl->fensures)[i];
+ if (e.id)
+ {
+ funcdecl->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 (funcdecl->fensure && f->next->ty != Tvoid)
+ funcdecl->buildResultVar(scout, f->next);
+
+ fens = statementSemantic(fens, sc2);
+ blockExit(fens, funcdecl, false);
+
+ sc2 = sc2->pop();
+
+ if (global.params.useOut == CHECKENABLEoff)
+ fens = NULL;
+ }
+
+ if (funcdecl->fbody && funcdecl->fbody->isErrorStatement())
+ ;
+ else
+ {
+ Statements *a = new Statements();
+
+ // Merge in initialization of 'out' parameters
+ if (funcdecl->parameters)
+ {
+ for (size_t i = 0; i < funcdecl->parameters->length; i++)
+ {
+ VarDeclaration *v = (*funcdecl->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 (funcdecl->v_argptr)
+ {
+ // Handled in FuncDeclaration::toObjFile
+ funcdecl->v_argptr->_init = new VoidInitializer(funcdecl->loc);
+ }
+
+ if (_arguments)
+ {
+ /* Advance to elements[] member of TypeInfo_Tuple with:
+ * _arguments = v_arguments.elements;
+ */
+ Expression *e = new VarExp(Loc(), funcdecl->v_arguments);
+ e = new DotIdExp(Loc(), e, Id::elements);
+ e = new ConstructExp(Loc(), _arguments, e);
+ e = expressionSemantic(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 (funcdecl->fbody)
+ a->push(funcdecl->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);
+ funcdecl->returnLabel->statement = ls;
+ a->push(funcdecl->returnLabel->statement);
+
+ if (f->next->ty != Tvoid && funcdecl->vresult)
+ {
+ // Create: return vresult;
+ Expression *e = new VarExp(Loc(), funcdecl->vresult);
+ if (funcdecl->tintro)
+ {
+ e = e->implicitCastTo(sc, funcdecl->tintro->nextOf());
+ e = expressionSemantic(e, sc);
+ }
+ ReturnStatement *s = new ReturnStatement(Loc(), e);
+ a->push(s);
+ }
+ }
+ if (addReturn0(funcdecl))
+ {
+ // 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 (funcdecl->parameters)
+ {
+ for (size_t i = 0; i < funcdecl->parameters->length; i++)
+ {
+ VarDeclaration *v = (*funcdecl->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 = statementSemantic(s, sc2);
+
+ bool isnothrow = f->isnothrow & !(funcdecl->flags & FUNCFLAGnothrowInprocess);
+ int blockexit = blockExit(s, funcdecl, isnothrow);
+ if (f->isnothrow && isnothrow && blockexit & BEthrow)
+ error(funcdecl->loc, "nothrow %s `%s` may throw", funcdecl->kind(), funcdecl->toPrettyChars());
+ if (funcdecl->flags & FUNCFLAGnothrowInprocess && blockexit & BEthrow)
+ f->isnothrow = false;
+ if (blockExit(sbody, funcdecl, 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
+ funcdecl->flags &= ~FUNCFLAGnothrowInprocess;
+
+ if (funcdecl->isSynchronized())
+ {
+ /* Wrap the entire function body in a synchronized statement
+ */
+ ClassDeclaration *cd = funcdecl->isThis() ? funcdecl->isThis()->isClassDeclaration() : funcdecl->parent->isClassDeclaration();
+
+ if (cd)
+ {
+ if (!global.params.is64bit &&
+ global.params.isWindows &&
+ !funcdecl->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 (funcdecl->isStatic())
+ {
+ // The monitor is in the ClassInfo
+ vsync = new DotIdExp(funcdecl->loc, resolve(funcdecl->loc, sc2, cd, false), Id::classinfo);
+ }
+ else
+ {
+ // 'this' is the monitor
+ vsync = new VarExp(funcdecl->loc, funcdecl->vthis);
+ }
+ sbody = new PeelStatement(sbody); // don't redo semantic()
+ sbody = new SynchronizedStatement(funcdecl->loc, vsync, sbody);
+ sbody = statementSemantic(sbody, sc2);
+ }
+ }
+ else
+ {
+ funcdecl->error("synchronized function %s must be a member of a class", funcdecl->toChars());
+ }
+ }
+
+ // If declaration has no body, don't set sbody to prevent incorrect codegen.
+ if (funcdecl->fbody || allowsContractWithoutBody(funcdecl))
+ funcdecl->fbody = sbody;
+ }
+
+ // Fix up forward-referenced gotos
+ if (funcdecl->gotos)
+ {
+ for (size_t i = 0; i < funcdecl->gotos->length; ++i)
+ {
+ (*funcdecl->gotos)[i]->checkLabel();
+ }
+ }
+
+ if (funcdecl->naked && (funcdecl->fensures || funcdecl->frequires))
+ funcdecl->error("naked assembly functions with contracts are not supported");
+
+ sc2->callSuper = 0;
+ sc2->pop();
+ }
+
+ if (funcdecl->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 (funcdecl->flags & FUNCFLAGpurityInprocess)
+ {
+ funcdecl->flags &= ~FUNCFLAGpurityInprocess;
+ if (funcdecl->type == f)
+ f = (TypeFunction *)f->copy();
+ f->purity = PUREfwdref;
+ }
+
+ if (funcdecl->flags & FUNCFLAGsafetyInprocess)
+ {
+ funcdecl->flags &= ~FUNCFLAGsafetyInprocess;
+ if (funcdecl->type == f)
+ f = (TypeFunction *)f->copy();
+ f->trust = TRUSTsafe;
+ }
+
+ if (funcdecl->flags & FUNCFLAGnogcInprocess)
+ {
+ funcdecl->flags &= ~FUNCFLAGnogcInprocess;
+ if (funcdecl->type == f)
+ f = (TypeFunction *)f->copy();
+ f->isnogc = true;
+ }
+
+ if (funcdecl->flags & FUNCFLAGreturnInprocess)
+ {
+ funcdecl->flags &= ~FUNCFLAGreturnInprocess;
+ if (funcdecl->storage_class & STCreturn)
+ {
+ if (funcdecl->type == f)
+ f = (TypeFunction *)f->copy();
+ f->isreturn = true;
+ }
+ }
+
+ funcdecl->flags &= ~FUNCFLAGinferScope;
+
+ // Infer STCscope
+ if (funcdecl->parameters)
+ {
+ size_t nfparams = f->parameterList.length();
+ assert(nfparams == funcdecl->parameters->length);
+ for (size_t u = 0; u < funcdecl->parameters->length; u++)
+ {
+ VarDeclaration *v = (*funcdecl->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 (funcdecl->vthis && funcdecl->vthis->storage_class & STCmaybescope)
+ {
+ funcdecl->vthis->storage_class &= ~STCmaybescope;
+ funcdecl->vthis->storage_class |= STCscope | STCscopeinferred;
+ f->isscope = true;
+ f->isscopeinferred = true;
+ }
+
+ // reset deco to apply inference result to mangled name
+ if (f != funcdecl->type)
+ f->deco = NULL;
+
+ // Do semantic type AFTER pure/nothrow inference.
+ if (!f->deco && funcdecl->ident != Id::xopEquals && funcdecl->ident != Id::xopCmp)
+ {
+ sc = sc->push();
+ if (funcdecl->isCtorDeclaration()) // Bugzilla #15665
+ sc->flags |= SCOPEctor;
+ sc->stc = 0;
+ sc->linkage = funcdecl->linkage; // Bugzilla 8496
+ funcdecl->type = typeSemantic(f, funcdecl->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.
+ */
+ funcdecl->semanticRun = PASSsemantic3done;
+ funcdecl->semantic3Errors = (global.errors != oldErrors) || (funcdecl->fbody && funcdecl->fbody->isErrorStatement());
+ if (funcdecl->type->ty == Terror)
+ funcdecl->errors = true;
+ //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl->parent->toChars(), funcdecl->toChars(), sc, funcdecl->loc.toChars());
+ //fflush(stdout);
+ }
+
+ void visit(Nspace *ns)
+ {
+ if (ns->semanticRun >= PASSsemantic3)
+ return;
+ ns->semanticRun = PASSsemantic3;
+ if (ns->members)
+ {
+ sc = sc->push(ns);
+ sc->linkage = LINKcpp;
+ for (size_t i = 0; i < ns->members->length; i++)
+ {
+ Dsymbol *s = (*ns->members)[i];
+ semantic3(s, sc);
+ }
+ sc->pop();
+ }
+ }
+
+ void visit(AttribDeclaration *ad)
+ {
+ Dsymbols *d = ad->include(sc);
+
+ if (d)
+ {
+ Scope *sc2 = ad->newScope(sc);
+
+ for (size_t i = 0; i < d->length; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ semantic3(s, sc2);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+ }
+
+ void visit(AggregateDeclaration *ad)
+ {
+ //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", ad->toChars(), ad->type->toChars(), ad->errors);
+ if (!ad->members)
+ return;
+
+ StructDeclaration *sd = ad->isStructDeclaration();
+ if (!sc) // from runDeferredSemantic3 for TypeInfo generation
+ {
+ assert(sd);
+ sd->semanticTypeInfoMembers();
+ return;
+ }
+
+ Scope *sc2 = ad->newScope(sc);
+
+ for (size_t i = 0; i < ad->members->length; i++)
+ {
+ Dsymbol *s = (*ad->members)[i];
+ semantic3(s, sc2);
+ }
+
+ sc2->pop();
+
+ // don't do it for unused deprecated types
+ // or error types
+ if (!ad->getRTInfo && Type::rtinfo &&
+ (!ad->isDeprecated() || global.params.useDeprecated != DIAGNOSTICerror) &&
+ (ad->type && ad->type->ty != Terror))
+ {
+ // Evaluate: RTinfo!type
+ Objects *tiargs = new Objects();
+ tiargs->push(ad->type);
+ TemplateInstance *ti = new TemplateInstance(ad->loc, Type::rtinfo, tiargs);
+
+ Scope *sc3 = ti->tempdecl->_scope->startCTFE();
+ sc3->tinst = sc->tinst;
+ sc3->minst = sc->minst;
+ if (ad->isDeprecated())
+ sc3->stc |= STCdeprecated;
+
+ dsymbolSemantic(ti, sc3);
+ semantic2(ti, sc3);
+ semantic3(ti, sc3);
+ Expression *e = resolve(Loc(), sc3, ti->toAlias(), false);
+
+ sc3->endCTFE();
+
+ e = e->ctfeInterpret();
+ ad->getRTInfo = e;
+ }
+
+ if (sd)
+ sd->semanticTypeInfoMembers();
+ ad->semanticRun = PASSsemantic3done;
+ }
+};
+
+/*************************************
+ * Does semantic analysis on function bodies.
+ */
+void semantic3(Dsymbol *dsym, Scope *sc)
+{
+ Semantic3Visitor v(sc);
+ dsym->accept(&v);
+}
/* 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.
bool walkPostorder(Expression *e, StoppableVisitor *v);
bool lambdaHasSideEffect(Expression *e);
-Expression *semantic(Expression *e, Scope *sc);
/**************************************************
* Front-end expression rewriting should create temporary variables for
Expression *de = new DeclarationExp(vd->loc, vd);
Expression *ve = new VarExp(vd->loc, vd);
- de = semantic(de, sc);
- ve = semantic(ve, sc);
+ de = expressionSemantic(de, sc);
+ ve = expressionSemantic(ve, sc);
*e0 = Expression::combine(*e0, de);
return ve;
/* 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.
StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Expression *semantic(Expression *e, Scope *sc);
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
Statement *makeTupleForeachStatic(Scope *sc, ForeachStatement *fs, bool needExpansion);
Identifier *fixupLabelName(Scope *sc, Identifier *ident)
Dsymbol *d = ((DeclarationExp *)exp)->declaration;
if (TemplateMixin *tm = d->isTemplateMixin())
{
- Expression *e = semantic(exp, sc);
+ Expression *e = expressionSemantic(exp, sc);
if (e->op == TOKerror || tm->errors)
{
Statements *a = new Statements();
}
else if (vd->ident == Id::withSym)
{
- s->deprecation("'switch' skips declaration of 'with' temporary at %s", vd->loc.toChars());
+ s->deprecation("`switch` skips declaration of `with` temporary at %s", vd->loc.toChars());
return true;
}
else
{
- s->deprecation("'switch' skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
+ s->deprecation("`switch` skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
return true;
}
* sfinally: if (!x) statement;
*/
VarDeclaration *v = copyToTemp(0, "__os", new IntegerExp(Loc(), 0, Type::tbool));
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
*sentry = new ExpStatement(loc, v);
Expression *e = new IntegerExp(Loc(), 1, Type::tbool);
{
if (!label->statement)
{
- error("label '%s' is undefined", label->toChars());
+ error("label `%s` is undefined", label->toChars());
return true;
}
/* 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.
class Expression;
class LabelDsymbol;
class Identifier;
+class Statement;
class IfStatement;
class ExpStatement;
class DefaultStatement;
class AsmStatement;
class GotoStatement;
class ScopeStatement;
+class Catch;
class TryCatchStatement;
class TryFinallyStatement;
class CaseStatement;
// Back end
struct code;
+Statement *statementSemantic(Statement *s, Scope *sc);
+Statement *semanticNoScope(Statement *s, Scope *sc);
+Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue);
+void catchSemantic(Catch *c, Scope *sc);
+
bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
--- /dev/null
+
+/* 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 "statement.h"
+#include "visitor.h"
+
+/* 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 *) { }
+};
+
/* 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.
Expression *checkAssignmentAsCondition(Expression *e);
TypeIdentifier *getThrowable();
-Expression *semantic(Expression *e, Scope *sc);
-Statement *semantic(Statement *s, Scope *sc);
-void semantic(Catch *c, Scope *sc);
-Statement *semanticNoScope(Statement *s, Scope *sc);
-Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue);
int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
class StatementSemanticVisitor : public Visitor
if (s->exp->op == TOKcomma)
((CommaExp *)s->exp)->allowCommaExp = true;
- s->exp = semantic(s->exp, sc);
+ s->exp = expressionSemantic(s->exp, sc);
s->exp = resolveProperties(sc, s->exp);
s->exp = s->exp->addDtorHook(sc);
if (checkNonAssignmentArrayOp(s->exp))
if (!a)
return;
Statement *s = new CompoundStatement(cs->loc, a);
- result = semantic(s, sc);
+ result = statementSemantic(s, sc);
}
void visit(CompoundStatement *cs)
cs->statements->insert(i, flt);
continue;
}
- s = semantic(s, sc);
+ s = statementSemantic(s, sc);
(*cs->statements)[i] = s;
if (s)
{
(*cs->statements)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally);
if (sentry)
{
- sentry = semantic(sentry, sc);
+ sentry = statementSemantic(sentry, sc);
cs->statements->insert(i, sentry);
i++;
}
if (sexception)
- sexception = semantic(sexception, sc);
+ sexception = statementSemantic(sexception, sc);
if (sexception)
{
if (i + 1 == cs->statements->length && !sfinally)
s = new TryCatchStatement(Loc(), body, catches);
if (sfinally)
s = new TryFinallyStatement(Loc(), s, sfinally);
- s = semantic(s, sc);
+ s = statementSemantic(s, sc);
cs->statements->setDim(i + 1);
cs->statements->push(s);
}
Statement *body = new CompoundStatement(Loc(), a);
s = new TryFinallyStatement(Loc(), body, sfinally);
- s = semantic(s, sc);
+ s = statementSemantic(s, sc);
cs->statements->setDim(i + 1);
cs->statements->push(s);
break;
if (s)
{
//printf("[%d]: %s\n", i, s->toChars());
- s = semantic(s, scd);
+ s = statementSemantic(s, scd);
(*uls->statements)[i] = s;
if (s && !serror)
ss->statement = new CompoundStatement(ss->loc, a);
}
- ss->statement = semantic(ss->statement, sc);
+ ss->statement = statementSemantic(ss->statement, sc);
if (ss->statement)
{
if (ss->statement->isErrorStatement())
if (sfinally)
{
//printf("adding sfinally\n");
- sfinally = semantic(sfinally, sc);
+ sfinally = statementSemantic(sfinally, sc);
ss->statement = new CompoundStatement(ss->loc, ss->statement, sfinally);
}
}
sc = sc->push(ss->sym);
sc->sbreak = ss;
sc->scontinue = ss;
- ss->statement = semantic(ss->statement, sc);
+ ss->statement = statementSemantic(ss->statement, sc);
sc = sc->pop();
result = ss->statement;
}
/* Rewrite as a for(;condition;) loop
*/
Statement *s = new ForStatement(ws->loc, NULL, ws->condition, NULL, ws->_body, ws->endloc);
- s = semantic(s, sc);
+ s = statementSemantic(s, sc);
result = s;
}
// check in syntax level
ds->condition = checkAssignmentAsCondition(ds->condition);
- ds->condition = semantic(ds->condition, sc);
+ ds->condition = expressionSemantic(ds->condition, sc);
ds->condition = resolveProperties(sc, ds->condition);
if (checkNonAssignmentArrayOp(ds->condition))
ds->condition = new ErrorExp();
ainit->push(fs);
Statement *s = new CompoundStatement(fs->loc, ainit);
s = new ScopeStatement(fs->loc, s, fs->endloc);
- s = semantic(s, sc);
+ s = statementSemantic(s, sc);
if (!s->isErrorStatement())
{
if (LabelStatement *ls = checkLabeledLoop(sc, fs))
// check in syntax level
fs->condition = checkAssignmentAsCondition(fs->condition);
- fs->condition = semantic(fs->condition, sc);
+ fs->condition = expressionSemantic(fs->condition, sc);
fs->condition = resolveProperties(sc, fs->condition);
if (checkNonAssignmentArrayOp(fs->condition))
fs->condition = new ErrorExp();
{
if (fs->increment->op == TOKcomma)
((CommaExp *)fs->increment)->allowCommaExp = true;
- fs->increment = semantic(fs->increment, sc);
+ fs->increment = expressionSemantic(fs->increment, sc);
fs->increment = resolveProperties(sc, fs->increment);
if (checkNonAssignmentArrayOp(fs->increment))
fs->increment = new ErrorExp();
p->type = Type::tsize_t;
}
}
- p->type = p->type->semantic(loc, sc);
+ p->type = typeSemantic(p->type, loc, sc);
TY keyty = p->type->ty;
if (keyty != Tint32 && keyty != Tuns32)
{
0, e->type, ident, e, NULL);
Identifier *field = Identifier::idPool("tuple");
Expression *access = new DotIdExp(loc, e, field);
- access = semantic(access, sc);
+ access = expressionSemantic(access, sc);
if (!tuple)
return false;
//printf("%s\n", tuple->toChars());
{
Parameter *cp = (*fs->parameters)[l];
Expression *init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type::tsize_t));
- init_ = semantic(init_, sc);
+ init_ = expressionSemantic(init_, sc);
assert(init_->type);
declareVariable(fs, paramtype, te, needExpansion, isStatic, stmts, decls,
p->storageClass, init_->type, cp->ident, init_, NULL);
Type *paramtype = (*fs->parameters)[dim-1]->type;
if (paramtype)
{
- paramtype = paramtype->semantic(loc, sc);
+ paramtype = typeSemantic(paramtype, loc, sc);
if (paramtype->ty == Terror)
return false;
}
fs->func = fs->func->fes->func;
VarDeclaration *vinit = NULL;
- fs->aggr = semantic(fs->aggr, sc);
+ fs->aggr = expressionSemantic(fs->aggr, sc);
fs->aggr = resolveProperties(sc, fs->aggr);
fs->aggr = fs->aggr->optimize(WANTvalue);
if (fs->aggr->op == TOKerror)
{
// Bugzilla 14653: Extend the life of rvalue aggregate till the end of foreach.
vinit = copyToTemp(STCrvalue, "__aggr", fs->aggr);
- vinit->semantic(sc);
+ dsymbolSemantic(vinit, sc);
fs->aggr = new VarExp(fs->aggr->loc, vinit);
}
}
if (vinit)
result = new CompoundStatement(loc, new ExpStatement(loc, vinit), result);
- result = semantic(result, sc);
+ result = statementSemantic(result, sc);
return;
}
for (size_t i = 0; i < dim; i++)
{
Parameter *p = (*fs->parameters)[i];
- p->type = p->type->semantic(loc, sc2);
+ p->type = typeSemantic(p->type, loc, sc2);
p->type = p->type->addStorageClass(p->storageClass);
}
IntRange dimrange = getIntRange(ta->dim);
if (!IntRange::fromType(var->type).contains(dimrange))
{
- fs->error("index type '%s' cannot cover index range 0..%llu", p->type->toChars(), ta->dim->toInteger());
+ fs->error("index type `%s` cannot cover index range 0..%llu", p->type->toChars(), ta->dim->toInteger());
goto Lerror2;
}
fs->key->range = new IntRange(SignExtendedNumber(0), dimrange.imax);
s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
if (LabelStatement *ls = checkLabeledLoop(sc, fs)) // Bugzilla 15450: don't use sc2
ls->gotoTarget = s;
- s = semantic(s, sc2);
+ s = statementSemantic(s, sc2);
break;
}
else
{
r = copyToTemp(0, "__r", fs->aggr);
- r->semantic(sc);
+ dsymbolSemantic(r, sc);
init = new ExpStatement(loc, r);
if (vinit)
init = new CompoundStatement(loc, new ExpStatement(loc, vinit), init);
else
{
VarDeclaration *vd = copyToTemp(STCref, "__front", einit);
- vd->semantic(sc);
+ dsymbolSemantic(vd, sc);
makeargs = new ExpStatement(loc, vd);
Type *tfront = NULL;
Expression *exp = (*exps)[i];
if (!p->type)
p->type = exp->type;
- p->type = p->type->addStorageClass(p->storageClass)->semantic(loc, sc2);
+ p->type = typeSemantic(p->type->addStorageClass(p->storageClass), loc, sc2);
if (!exp->implicitConvTo(p->type))
goto Lrangeerr;
s = new ForStatement(loc, init, condition, increment, forbody, fs->endloc);
if (LabelStatement *ls = checkLabeledLoop(sc, fs))
ls->gotoTarget = s;
- s = semantic(s, sc2);
+ s = statementSemantic(s, sc2);
break;
Lrangeerr:
if (fdapply)
{
assert(fdapply->type && fdapply->type->ty == Tfunction);
- tfld = (TypeFunction *)fdapply->type->semantic(loc, sc2);
+ tfld = (TypeFunction *)typeSemantic(fdapply->type, loc, sc2);
goto Lget;
}
else if (tab->ty == Tdelegate)
Parameter *p = tfld->parameterList[0];
if (p->type && p->type->ty == Tdelegate)
{
- Type *t = p->type->semantic(loc, sc2);
+ Type *t = typeSemantic(p->type, loc, sc2);
assert(t->ty == Tdelegate);
tfld = (TypeFunction *)t->nextOf();
}
StorageClass stc = STCref;
Identifier *id;
- p->type = p->type->semantic(loc, sc2);
+ p->type = typeSemantic(p->type, loc, sc2);
p->type = p->type->addStorageClass(p->storageClass);
if (tfld)
{
FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, Loc(), tfld, TOKdelegate, fs);
fld->fbody = fs->_body;
Expression *flde = new FuncExp(loc, fld);
- flde = semantic(flde, sc2);
+ flde = expressionSemantic(flde, sc2);
fld->tookAddressOf = 0;
// Resolve any forward referenced goto's
if (vinit)
{
e = new DeclarationExp(loc, vinit);
- e = semantic(e, sc2);
+ e = expressionSemantic(e, sc2);
if (e->op == TOKerror)
goto Lerror2;
}
fs->aggr = ((DelegateExp *)fs->aggr)->e1;
}
ec = new CallExp(loc, fs->aggr, flde);
- ec = semantic(ec, sc2);
+ ec = expressionSemantic(ec, sc2);
if (ec->op == TOKerror)
goto Lerror2;
if (ec->type != Type::tint32)
*/
ec = new DotIdExp(loc, fs->aggr, sapply->ident);
ec = new CallExp(loc, ec, flde);
- ec = semantic(ec, sc2);
+ ec = expressionSemantic(ec, sc2);
if (ec->op == TOKerror)
goto Lerror2;
if (ec->type != Type::tint32)
s = new CompoundStatement(loc, a);
s = new SwitchStatement(loc, e, s, false);
}
- s = semantic(s, sc2);
+ s = statementSemantic(s, sc2);
break;
}
case Terror:
{
//printf("ForeachRangeStatement::semantic() %p\n", fs);
Loc loc = fs->loc;
- fs->lwr = semantic(fs->lwr, sc);
+ fs->lwr = expressionSemantic(fs->lwr, sc);
fs->lwr = resolveProperties(sc, fs->lwr);
fs->lwr = fs->lwr->optimize(WANTvalue);
if (!fs->lwr->type)
return setError();
}
- fs->upr = semantic(fs->upr, sc);
+ fs->upr = expressionSemantic(fs->upr, sc);
fs->upr = resolveProperties(sc, fs->upr);
fs->upr = fs->upr->optimize(WANTvalue);
if (!fs->upr->type)
if (fs->prm->type)
{
- fs->prm->type = fs->prm->type->semantic(loc, sc);
+ fs->prm->type = typeSemantic(fs->prm->type, loc, sc);
fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
fs->lwr = fs->lwr->implicitCastTo(sc, fs->prm->type);
{
// See if upr-1 fits in prm->type
Expression *limit = new MinExp(loc, fs->upr, new IntegerExp(1));
- limit = semantic(limit, sc);
+ limit = expressionSemantic(limit, sc);
limit = limit->optimize(WANTvalue);
if (!limit->implicitConvTo(fs->prm->type))
{
ForStatement *s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
if (LabelStatement *ls = checkLabeledLoop(sc, fs))
ls->gotoTarget = s;
- result = semantic(s, sc);
+ result = statementSemantic(s, sc);
}
void visit(IfStatement *ifs)
ifs->match = new VarDeclaration(ifs->loc, ifs->prm->type, ifs->prm->ident, ei);
ifs->match->parent = sc->func;
ifs->match->storage_class |= ifs->prm->storageClass;
- ifs->match->semantic(scd);
+ dsymbolSemantic(ifs->match, scd);
DeclarationExp *de = new DeclarationExp(ifs->loc, ifs->match);
VarExp *ve = new VarExp(ifs->loc, ifs->match);
ifs->condition = new CommaExp(ifs->loc, de, ve);
- ifs->condition = semantic(ifs->condition, scd);
+ ifs->condition = expressionSemantic(ifs->condition, scd);
if (ifs->match->edtor)
{
if (ifs->condition->op == TOKdotid)
((DotIdExp *)ifs->condition)->noderef = true;
- ifs->condition = semantic(ifs->condition, sc);
+ ifs->condition = expressionSemantic(ifs->condition, sc);
ifs->condition = resolveProperties(sc, ifs->condition);
ifs->condition = ifs->condition->addDtorHook(sc);
}
{
sc = sc->push();
sc->flags |= SCOPEdebug;
- cs->ifbody = semantic(cs->ifbody, sc);
+ cs->ifbody = statementSemantic(cs->ifbody, sc);
sc->pop();
}
else
- cs->ifbody = semantic(cs->ifbody, sc);
+ cs->ifbody = statementSemantic(cs->ifbody, sc);
result = cs->ifbody;
}
else
{
if (cs->elsebody)
- cs->elsebody = semantic(cs->elsebody, sc);
+ cs->elsebody = statementSemantic(cs->elsebody, sc);
result = cs->elsebody;
}
}
Expression *e = (*ps->args)[i];
sc = sc->startCTFE();
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
// pragma(msg) is allowed to contain types as well as expressions
Expression *e = (*ps->args)[0];
sc = sc->startCTFE();
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
Dsymbol *sa = getDsymbol(e);
if (!sa || !sa->isFuncDeclaration())
{
- ps->error("function name expected for start address, not '%s'", e->toChars());
+ ps->error("function name expected for start address, not `%s`", e->toChars());
goto Lerror;
}
if (ps->_body)
{
- ps->_body = semantic(ps->_body, sc);
+ ps->_body = statementSemantic(ps->_body, sc);
if (ps->_body->isErrorStatement())
{
result = ps->_body;
ps->error("`pragma(%s)` is missing a terminating `;`", ps->ident->toChars());
return setError();
}
- ps->_body = semantic(ps->_body, sc);
+ ps->_body = statementSemantic(ps->_body, sc);
}
result = ps->_body;
return;
void visit(StaticAssertStatement *s)
{
- s->sa->semantic2(sc);
+ semantic2(s->sa, sc);
}
void visit(SwitchStatement *ss)
return;
}
bool conditionError = false;
- ss->condition = semantic(ss->condition, sc);
+ ss->condition = expressionSemantic(ss->condition, sc);
ss->condition = resolveProperties(sc, ss->condition);
Type *att = NULL;
if (ss->condition->op != TOKerror)
{
- ss->error("'%s' must be of integral or string type, it is a %s",
+ ss->error("`%s` must be of integral or string type, it is a %s",
ss->condition->toChars(), ss->condition->type->toChars());
conditionError = true;
break;
ss->cases = new CaseStatements();
sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
- ss->_body = semantic(ss->_body, sc);
+ ss->_body = statementSemantic(ss->_body, sc);
sc->noctor--;
if (conditionError || (ss->_body && ss->_body->isErrorStatement()))
ss->hasNoDefault = 1;
if (!ss->isFinal && (!ss->_body || !ss->_body->isErrorStatement()))
- ss->error("switch statement without a default; use 'final switch' or add 'default: assert(0);' or add 'default: break;'");
+ ss->error("switch statement without a default; use `final switch` or add `default: assert(0);` or add `default: break;`");
// Generate runtime error if the default is hit
Statements *a = new Statements();
//printf("CaseStatement::semantic() %s\n", cs->toChars());
sc = sc->startCTFE();
- cs->exp = semantic(cs->exp, sc);
+ cs->exp = expressionSemantic(cs->exp, sc);
cs->exp = resolveProperties(sc, cs->exp);
sc = sc->endCTFE();
if (sw)
cs->error("case not in switch statement");
errors = true;
}
- cs->statement = semantic(cs->statement, sc);
+ cs->statement = statementSemantic(cs->statement, sc);
if (cs->statement->isErrorStatement())
{
result = cs->statement;
}
sc = sc->startCTFE();
- crs->first = semantic(crs->first, sc);
+ crs->first = expressionSemantic(crs->first, sc);
crs->first = resolveProperties(sc, crs->first);
sc = sc->endCTFE();
crs->first = crs->first->implicitCastTo(sc, sw->condition->type);
crs->first = crs->first->ctfeInterpret();
sc = sc->startCTFE();
- crs->last = semantic(crs->last, sc);
+ crs->last = expressionSemantic(crs->last, sc);
crs->last = resolveProperties(sc, crs->last);
sc = sc->endCTFE();
crs->last = crs->last->implicitCastTo(sc, sw->condition->type);
if (crs->first->op == TOKerror || crs->last->op == TOKerror || errors)
{
if (crs->statement)
- semantic(crs->statement, sc);
+ statementSemantic(crs->statement, sc);
return setError();
}
statements->push(cs);
}
Statement *s = new CompoundStatement(crs->loc, statements);
- s = semantic(s, sc);
+ s = statementSemantic(s, sc);
result = s;
}
ds->error("default not in switch statement");
errors = true;
}
- ds->statement = semantic(ds->statement, sc);
+ ds->statement = statementSemantic(ds->statement, sc);
if (errors || ds->statement->isErrorStatement())
return setError();
if (gcs->exp)
{
- gcs->exp = semantic(gcs->exp, sc);
+ gcs->exp = expressionSemantic(gcs->exp, sc);
gcs->exp = gcs->exp->implicitCastTo(sc, sc->sw->condition->type);
gcs->exp = gcs->exp->optimize(WANTvalue);
if (gcs->exp->op == TOKerror)
rs->exp = inferType(rs->exp, tret);
else if (fld && fld->treq)
rs->exp = inferType(rs->exp, fld->treq->nextOf()->nextOf());
- rs->exp = semantic(rs->exp, sc);
+ rs->exp = expressionSemantic(rs->exp, sc);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
if (rs->exp->op == TOKtype)
errors = true;
rs->exp = new CastExp(rs->loc, rs->exp, Type::tvoid);
- rs->exp = semantic(rs->exp, sc);
+ rs->exp = expressionSemantic(rs->exp, sc);
}
/* Replace:
Statement *s = ls->statement;
if (!s || !s->hasBreak())
- bs->error("label '%s' has no break", bs->ident->toChars());
+ bs->error("label `%s` has no break", bs->ident->toChars());
else if (ls->tf != sc->tf)
bs->error("cannot break out of finally block");
else
return setError();
}
}
- bs->error("enclosing label '%s' for break not found", bs->ident->toChars());
+ bs->error("enclosing label `%s` for break not found", bs->ident->toChars());
return setError();
}
else if (!sc->sbreak)
Statement *s = ls->statement;
if (!s || !s->hasContinue())
- cs->error("label '%s' has no continue", cs->ident->toChars());
+ cs->error("label `%s` has no continue", cs->ident->toChars());
else if (ls->tf != sc->tf)
cs->error("cannot continue out of finally block");
else
return setError();
}
}
- cs->error("enclosing label '%s' for continue not found", cs->ident->toChars());
+ cs->error("enclosing label `%s` for continue not found", cs->ident->toChars());
return setError();
}
else if (!sc->scontinue)
{
if (ss->exp)
{
- ss->exp = semantic(ss->exp, sc);
+ ss->exp = expressionSemantic(ss->exp, sc);
ss->exp = resolveProperties(sc, ss->exp);
ss->exp = ss->exp->optimize(WANTvalue);
ss->exp = checkGC(sc, ss->exp);
ClassDeclaration *cd = ss->exp->type->isClassHandle();
if (!cd)
{
- ss->error("can only synchronize on class objects, not '%s'", ss->exp->type->toChars());
+ ss->error("can only synchronize on class objects, not `%s`", ss->exp->type->toChars());
return setError();
}
else if (cd->isInterfaceDeclaration())
}
Type *t = ClassDeclaration::object->type;
- t = t->semantic(Loc(), sc)->toBasetype();
+ t = typeSemantic(t, Loc(), sc)->toBasetype();
assert(t->ty == Tclass);
ss->exp = new CastExp(ss->loc, ss->exp, t);
- ss->exp = semantic(ss->exp, sc);
+ ss->exp = expressionSemantic(ss->exp, sc);
}
/* Rewrite as:
* try { body } finally { _d_monitorexit(tmp); }
*/
VarDeclaration *tmp = copyToTemp(0, "__sync", ss->exp);
- tmp->semantic(sc);
+ dsymbolSemantic(tmp, sc);
Statements *cs = new Statements();
cs->push(new ExpStatement(ss->loc, tmp));
cs->push(s);
s = new CompoundStatement(ss->loc, cs);
- result = semantic(s, sc);
+ result = statementSemantic(s, sc);
return;
}
else
* Backend optimizer could remove this unused variable.
*/
VarDeclaration *v = new VarDeclaration(ss->loc, Type::tvoidptr, Identifier::generateId("__sync"), NULL);
- v->semantic(sc);
+ dsymbolSemantic(v, sc);
cs->push(new ExpStatement(ss->loc, v));
Parameters* args = new Parameters;
FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow);
Expression *e = new AddrExp(ss->loc, tmpExp);
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), e);
e->type = Type::tvoid; // do not run semantic on e
cs->push(new ExpStatement(ss->loc, e));
FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit, STCnothrow);
- e = semantic(tmpExp, sc);
+ e = expressionSemantic(tmpExp, sc);
e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), e);
e->type = Type::tvoid; // do not run semantic on e
Statement *s = new ExpStatement(ss->loc, e);
cs->push(s);
s = new CompoundStatement(ss->loc, cs);
- result = semantic(s, sc);
+ result = statementSemantic(s, sc);
return;
}
Lbody:
if (ss->_body)
- ss->_body = semantic(ss->_body, sc);
+ ss->_body = statementSemantic(ss->_body, sc);
if (ss->_body && ss->_body->isErrorStatement())
{
result = ss->_body;
Initializer *init;
//printf("WithStatement::semantic()\n");
- ws->exp = semantic(ws->exp, sc);
+ ws->exp = expressionSemantic(ws->exp, sc);
ws->exp = resolveProperties(sc, ws->exp);
ws->exp = ws->exp->optimize(WANTvalue);
ws->exp = checkGC(sc, ws->exp);
if (t->ty == Tpointer)
{
ws->exp = new PtrExp(ws->loc, ws->exp);
- ws->exp = semantic(ws->exp, sc);
+ ws->exp = expressionSemantic(ws->exp, sc);
t = ws->exp->type->toBasetype();
}
{
init = new ExpInitializer(ws->loc, ws->exp);
ws->wthis = new VarDeclaration(ws->loc, ws->exp->type, Id::withSym, init);
- ws->wthis->semantic(sc);
+ dsymbolSemantic(ws->wthis, sc);
sym = new WithScopeSymbol(ws);
sym->parent = sc->scopesym;
* }
*/
VarDeclaration *tmp = copyToTemp(0, "__withtmp", ws->exp);
- tmp->semantic(sc);
+ dsymbolSemantic(tmp, sc);
ExpStatement *es = new ExpStatement(ws->loc, tmp);
ws->exp = new VarExp(ws->loc, tmp);
Statement *ss = new ScopeStatement(ws->loc, new CompoundStatement(ws->loc, es, ws), ws->endloc);
- result = semantic(ss, sc);
+ result = statementSemantic(ss, sc);
return;
}
Expression *e = ws->exp->addressOf();
init = new ExpInitializer(ws->loc, e);
ws->wthis = new VarDeclaration(ws->loc, e->type, Id::withSym, init);
- ws->wthis->semantic(sc);
+ dsymbolSemantic(ws->wthis, sc);
sym = new WithScopeSymbol(ws);
// Need to set the scope to make use of resolveAliasThis
sym->setScope(sc);
}
else
{
- ws->error("with expressions must be aggregate types or pointers to them, not '%s'", olde->type->toChars());
+ ws->error("with expressions must be aggregate types or pointers to them, not `%s`", olde->type->toChars());
return setError();
}
}
sym->_scope = sc;
sc = sc->push(sym);
sc->insert(sym);
- ws->_body = semantic(ws->_body, sc);
+ ws->_body = statementSemantic(ws->_body, sc);
sc->pop();
if (ws->_body && ws->_body->isErrorStatement())
{
for (size_t i = 0; i < tcs->catches->length; i++)
{
Catch *c = (*tcs->catches)[i];
- semantic(c, sc);
+ catchSemantic(c, sc);
if (c->errors)
{
catchErrors = true;
void visit(TryFinallyStatement *tfs)
{
//printf("TryFinallyStatement::semantic()\n");
- tfs->_body = semantic(tfs->_body, sc);
+ tfs->_body = statementSemantic(tfs->_body, sc);
sc = sc->push();
sc->tf = tfs;
sc->sbreak = NULL;
FuncDeclaration *fd = sc->parent->isFuncDeclaration();
fd->hasReturnExp |= 2;
- ts->exp = semantic(ts->exp, sc);
+ ts->exp = expressionSemantic(ts->exp, sc);
ts->exp = resolveProperties(sc, ts->exp);
ts->exp = checkGC(sc, ts->exp);
if (ts->exp->op == TOKerror)
{
sc = sc->push();
sc->flags |= SCOPEdebug;
- ds->statement = semantic(ds->statement, sc);
+ ds->statement = statementSemantic(ds->statement, sc);
sc->pop();
}
result = ds->statement;
LabelDsymbol *ls2 = fd->searchLabel(ls->ident);
if (ls2->statement)
{
- ls->error("label '%s' already defined", ls2->toChars());
+ ls->error("label `%s` already defined", ls2->toChars());
return setError();
}
else
}
sc->slabel = ls;
if (ls->statement)
- ls->statement = semantic(ls->statement, sc);
+ ls->statement = statementSemantic(ls->statement, sc);
sc->pop();
result = ls;
for (size_t i = 0; i < cas->statements->length; i++)
{
Statement *s = (*cas->statements)[i];
- (*cas->statements)[i] = s ? semantic(s, sc) : NULL;
+ (*cas->statements)[i] = s ? statementSemantic(s, sc) : NULL;
}
assert(sc->func);
// use setImpure/setGC when the deprecation cycle is over
PURE purity;
if (!(cas->stc & STCpure) && (purity = sc->func->isPureBypassingInference()) != PUREimpure && purity != PUREfwdref)
- cas->deprecation("asm statement is assumed to be impure - mark it with 'pure' if it is not");
+ cas->deprecation("asm statement is assumed to be impure - mark it with `pure` if it is not");
if (!(cas->stc & STCnogc) && sc->func->isNogcBypassingInference())
- cas->deprecation("asm statement is assumed to use the GC - mark it with '@nogc' if it does not");
+ cas->deprecation("asm statement is assumed to use the GC - mark it with `@nogc` if it does not");
if (!(cas->stc & (STCtrusted|STCsafe)) && sc->func->setUnsafe())
- cas->error("asm statement is assumed to be @system - mark it with '@trusted' if it is not");
+ cas->error("asm statement is assumed to be @system - mark it with `@trusted` if it is not");
sc->pop();
result = cas;
s->aliasdecls.push(ad);
}
- s->semantic(sc);
+ dsymbolSemantic(s, sc);
// https://issues.dlang.org/show_bug.cgi?id=19942
// If the module that's being imported doesn't exist, don't add it to the symbol table
// for the current scope.
}
};
-Statement *semantic(Statement *s, Scope *sc)
+Statement *statementSemantic(Statement *s, Scope *sc)
{
StatementSemanticVisitor v = StatementSemanticVisitor(sc);
s->accept(&v);
return v.result;
}
-void semantic(Catch *c, Scope *sc)
+void catchSemantic(Catch *c, Scope *sc)
{
//printf("Catch::semantic(%s)\n", ident->toChars());
// reference .object.Throwable
c->type = getThrowable();
}
- c->type = c->type->semantic(c->loc, sc);
+ c->type = typeSemantic(c->type, c->loc, sc);
if (c->type == Type::terror)
c->errors = true;
else
ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
if (!cd)
{
- error(c->loc, "can only catch class objects, not '%s'", c->type->toChars());
+ error(c->loc, "can only catch class objects, not `%s`", c->type->toChars());
c->errors = true;
}
else if (cd->isCPPclass())
}
else if (cd != ClassDeclaration::throwable && !ClassDeclaration::throwable->isBaseOf(cd, NULL))
{
- error(c->loc, "can only catch class objects derived from Throwable, not '%s'", c->type->toChars());
+ error(c->loc, "can only catch class objects derived from Throwable, not `%s`", c->type->toChars());
c->errors = true;
}
else if (sc->func && !sc->intypeof && !c->internalCatch &&
cd != ClassDeclaration::exception && !ClassDeclaration::exception->isBaseOf(cd, NULL) &&
sc->func->setUnsafe())
{
- error(c->loc, "can only catch class objects derived from Exception in @safe code, not '%s'", c->type->toChars());
+ error(c->loc, "can only catch class objects derived from Exception in @safe code, not `%s`", c->type->toChars());
c->errors = true;
}
if (c->ident)
{
c->var = new VarDeclaration(c->loc, c->type, c->ident, NULL);
- c->var->semantic(sc);
+ dsymbolSemantic(c->var, sc);
sc->insert(c->var);
}
- c->handler = semantic(c->handler, sc);
+ c->handler = statementSemantic(c->handler, sc);
if (c->handler && c->handler->isErrorStatement())
c->errors = true;
}
{
s = new CompoundStatement(s->loc, s); // so scopeCode() gets called
}
- s = semantic(s, sc);
+ s = statementSemantic(s, sc);
return s;
}
/* 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.
#include "template.h"
#include "declaration.h"
-Expression *semantic(Expression *e, Scope *sc);
bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
/********************************* AttribDeclaration ****************************/
// we didn't add anything
}
-void StaticAssert::semantic(Scope *)
-{
-}
-
-void StaticAssert::semantic2(Scope *sc)
-{
- //printf("StaticAssert::semantic2() %s\n", toChars());
- ScopeDsymbol *sds = new ScopeDsymbol();
- sc = sc->push(sds);
- sc->tinst = NULL;
- sc->minst = NULL;
-
- bool errors = false;
- bool result = evalStaticCondition(sc, exp, exp, errors);
- sc = sc->pop();
- if (errors)
- {
- errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars());
- }
- else if (!result)
- {
- if (msg)
- {
- sc = sc->startCTFE();
- msg = ::semantic(msg, sc);
- msg = resolveProperties(sc, msg);
- sc = sc->endCTFE();
- msg = msg->ctfeInterpret();
- if (StringExp * se = msg->toStringExp())
- {
- // same with pragma(msg)
- se = se->toUTF8(sc);
- error("\"%.*s\"", (int)se->len, (char *)se->string);
- }
- else
- error("%s", msg->toChars());
- }
- else
- error("(%s) is false", exp->toChars());
- if (sc->tinst)
- sc->tinst->printInstantiationTrace();
- if (!global.gag)
- fatal();
- }
-}
-
bool StaticAssert::oneMember(Dsymbol **ps, Identifier *)
{
//printf("StaticAssert::oneMember())\n");
/* 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.
Dsymbol *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
bool oneMember(Dsymbol **ps, Identifier *ident);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
/* 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.
#include "mtype.h"
#include "scope.h"
-Expression *semantic(Expression *e, Scope *sc);
-
/********************************************
* Semantically analyze and then evaluate a static condition at compile time.
* This is special because short circuit operators &&, || and ?: at the top
sc = sc->startCTFE();
sc->flags |= SCOPEcondition;
- e = semantic(e, sc);
+ e = expressionSemantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
/* Compiler implementation of the D programming language
- * Copyright (C) 2013-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2013-2021 by The D Language Foundation, All Rights Reserved
* written by Iain Buclaw
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
/* 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.
enum MATCH;
enum PASS;
+bool tpsemantic(TemplateParameter *tp, Scope *sc, TemplateParameters *parameters);
+RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters);
+void templateInstanceSemantic(TemplateInstance *tempinst, Scope *sc, Expressions *fargs);
+
class Tuple : public RootObject
{
public:
TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters,
Expression *constraint, Dsymbols *decldefs, bool ismixin = false, bool literal = false);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc);
bool overloadInsert(Dsymbol *s);
bool hasStaticCtorOrDtor();
const char *kind() const;
virtual TemplateParameter *syntaxCopy() = 0;
virtual bool declareParameter(Scope *sc) = 0;
- virtual bool semantic(Scope *sc, TemplateParameters *parameters) = 0;
virtual void print(RootObject *oarg, RootObject *oded) = 0;
virtual RootObject *specialization() = 0;
virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0;
TemplateTypeParameter *isTemplateTypeParameter();
TemplateParameter *syntaxCopy();
bool declareParameter(Scope *sc);
- bool semantic(Scope *sc, TemplateParameters *parameters);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
TemplateValueParameter *isTemplateValueParameter();
TemplateParameter *syntaxCopy();
bool declareParameter(Scope *sc);
- bool semantic(Scope *sc, TemplateParameters *parameters);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
TemplateAliasParameter *isTemplateAliasParameter();
TemplateParameter *syntaxCopy();
bool declareParameter(Scope *sc);
- bool semantic(Scope *sc, TemplateParameters *parameters);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
TemplateTupleParameter *isTemplateTupleParameter();
TemplateParameter *syntaxCopy();
bool declareParameter(Scope *sc);
- bool semantic(Scope *sc, TemplateParameters *parameters);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs);
static Objects *arraySyntaxCopy(Objects *objs);
Dsymbol *syntaxCopy(Dsymbol *);
- void semantic(Scope *sc, Expressions *fargs);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
- void semantic3(Scope *sc);
Dsymbol *toAlias(); // resolve real symbol
const char *kind() const;
bool oneMember(Dsymbol **ps, Identifier *ident);
TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs);
Dsymbol *syntaxCopy(Dsymbol *s);
- void semantic(Scope *sc);
- void semantic2(Scope *sc);
- void semantic3(Scope *sc);
const char *kind() const;
bool oneMember(Dsymbol **ps, Identifier *ident);
int apply(Dsymbol_apply_ft_t fp, void *param);
--- /dev/null
+
+/* 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 "template.h"
+#include "mtype.h"
+#include "scope.h"
+#include "visitor.h"
+
+bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
+
+class TemplateParameterSemanticVisitor : public Visitor
+{
+public:
+ Scope *sc;
+ TemplateParameters *parameters;
+ bool result;
+
+ TemplateParameterSemanticVisitor(Scope *sc, TemplateParameters *parameters)
+ {
+ this->sc = sc;
+ this->parameters = parameters;
+ this->result = false;
+ }
+
+ void visit(TemplateTypeParameter *ttp)
+ {
+ //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
+ if (ttp->specType && !reliesOnTident(ttp->specType, parameters))
+ {
+ ttp->specType = typeSemantic(ttp->specType, ttp->loc, sc);
+ }
+ result = !(ttp->specType && isError(ttp->specType));
+ }
+
+ void visit(TemplateValueParameter *tvp)
+ {
+ tvp->valType = typeSemantic(tvp->valType, tvp->loc, sc);
+
+ result = !isError(tvp->valType);
+ }
+
+ void visit(TemplateAliasParameter *tap)
+ {
+ if (tap->specType && !reliesOnTident(tap->specType, parameters))
+ {
+ tap->specType = typeSemantic(tap->specType, tap->loc, sc);
+ }
+ tap->specAlias = aliasParameterSemantic(tap->loc, sc, tap->specAlias, parameters);
+ result = !(tap->specType && isError(tap->specType)) &&
+ !(tap->specAlias && isError(tap->specAlias));
+ }
+
+ void visit(TemplateTupleParameter *)
+ {
+ result = true;
+ }
+};
+
+/************************************************
+ * Performs semantic on TemplateParameter AST nodes.
+ *
+ * Params:
+ * tp = element of `parameters` to be semantically analyzed
+ * sc = context
+ * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration`
+ * Returns:
+ * `true` if no errors
+ */
+bool tpsemantic(TemplateParameter *tp, Scope *sc, TemplateParameters *parameters)
+{
+ TemplateParameterSemanticVisitor v(sc, parameters);
+ tp->accept(&v);
+ return v.result;
+}
+
+/***********************************************
+ * Support function for performing semantic analysis on `TemplateAliasParameter`.
+ *
+ * Params:
+ * loc = location (for error messages)
+ * sc = context
+ * o = object to run semantic() on, the `TemplateAliasParameter`s `specAlias` or `defaultAlias`
+ * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration`
+ * Returns:
+ * object resulting from running `semantic` on `o`
+ */
+RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters)
+{
+ if (o)
+ {
+ Expression *ea = isExpression(o);
+ Type *ta = isType(o);
+ if (ta && (!parameters || !reliesOnTident(ta, parameters)))
+ {
+ Dsymbol *s = ta->toDsymbol(sc);
+ if (s)
+ o = s;
+ else
+ o = typeSemantic(ta, loc, sc);
+ }
+ else if (ea)
+ {
+ sc = sc->startCTFE();
+ ea = expressionSemantic(ea, sc);
+ sc = sc->endCTFE();
+ o = ea->ctfeInterpret();
+ }
+ }
+ return o;
+}
/* 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.
/* 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.
/* 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.
void freeFieldinit(Scope *sc);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
Package *resolveIsPackage(Dsymbol *sym);
-Expression *trySemantic(Expression *e, Scope *sc);
-Expression *semantic(Expression *e, Scope *sc);
Expression *typeToExpression(Type *t);
return f->isNested() ? True(e) : False(e);
}
- e->error("aggregate or function expected instead of '%s'", o->toChars());
+ e->error("aggregate or function expected instead of `%s`", o->toChars());
return new ErrorExp();
}
else if (e->ident == Id::isDisabled)
}
StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
- return semantic(se, sc);
+ return expressionSemantic(se, sc);
}
else if (e->ident == Id::getProtection || e->ident == Id::getVisibility)
{
return new ErrorExp();
}
if (s->semanticRun == PASSinit)
- s->semantic(NULL);
+ dsymbolSemantic(s, NULL);
const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names)
assert(protName);
StringExp *se = new StringExp(e->loc, const_cast<char *>(protName));
- return semantic(se, sc);
+ return expressionSemantic(se, sc);
}
else if (e->ident == Id::parent)
{
if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
td = td->overroot; // then get the start
Expression *ex = new TemplateExp(e->loc, td, f);
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
return ex;
}
{
// Directly translate to VarExp instead of FuncExp
Expression *ex = new VarExp(e->loc, fld, true);
- return semantic(ex, sc);
+ return expressionSemantic(ex, sc);
}
}
return new ErrorExp();
}
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
RootObject *oc = (*e->args)[1];
Dsymbol *symc = getDsymbol(oc);
if (!symc)
else
assert(0);
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
return ex;
}
else if (e->ident == Id::hasMember ||
if (ex->op == TOKdotid)
// Prevent semantic() from replacing Symbol with its initializer
((DotIdExp *)ex)->wantsym = true;
- ex = semantic(ex, scx);
+ ex = expressionSemantic(ex, scx);
scx->pop();
return ex;
}
{
unsigned errors = global.errors;
Expression *eorig = ex;
- ex = semantic(ex, scx);
+ ex = expressionSemantic(ex, scx);
if (errors < global.errors)
e->error("%s cannot be resolved", eorig->toChars());
//ex->print();
overloadApply(f, &p, &fptraits);
ex = new TupleExp(e->loc, exps);
- ex = semantic(ex, scx);
+ ex = expressionSemantic(ex, scx);
scx->pop();
return ex;
}
if (ad->aliasthis)
exps->push(new StringExp(e->loc, const_cast<char *>(ad->aliasthis->ident->toChars())));
Expression *ex = new TupleExp(e->loc, exps);
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
return ex;
}
else if (e->ident == Id::getAttributes)
Expressions *exps = udad ? udad->getAttributes() : new Expressions();
TupleExp *tup = new TupleExp(e->loc, exps);
- return semantic(tup, sc);
+ return expressionSemantic(tup, sc);
}
else if (e->ident == Id::getFunctionAttributes)
{
tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem);
TupleExp *tup = new TupleExp(e->loc, mods);
- return semantic(tup, sc);
+ return expressionSemantic(tup, sc);
}
else if (e->ident == Id::isReturnOnStack)
{
assert(0);
}
StringExp *se = new StringExp(e->loc, const_cast<char*>(style));
- return semantic(se, sc);
+ return expressionSemantic(se, sc);
}
else if (e->ident == Id::getParameterStorageClasses)
{
exps->push(new StringExp(e->loc, const_cast<char *>("scope")));
TupleExp *tup = new TupleExp(e->loc, exps);
- return semantic(tup, sc);
+ return expressionSemantic(tup, sc);
}
else if (e->ident == Id::getLinkage)
{
}
const char *linkage = linkageToChars(link);
StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage));
- return semantic(se, sc);
+ return expressionSemantic(se, sc);
}
else if (e->ident == Id::allMembers ||
e->ident == Id::derivedMembers)
if (cd && e->ident == Id::allMembers)
{
if (cd->semanticRun < PASSsemanticdone)
- cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference
+ dsymbolSemantic(cd, NULL); // Bugzilla 13668: Try to resolve forward reference
struct PushBaseMembers
{
* [ __traits(allMembers, ...) ]
*/
Expression *ex = new TupleExp(e->loc, exps);
- ex = semantic(ex, sc);
+ ex = expressionSemantic(ex, sc);
return ex;
}
else if (e->ident == Id::compiles)
t->resolve(e->loc, sc2, &ex, &t, &s);
if (t)
{
- t->semantic(e->loc, sc2);
+ typeSemantic(t, e->loc, sc2);
if (t->ty == Terror)
err = true;
}
}
if (ex)
{
- ex = semantic(ex, sc2);
+ ex = expressionSemantic(ex, sc2);
ex = resolvePropertiesOnly(sc2, ex);
ex = ex->optimize(WANTvalue);
if (sc2->func && sc2->func->type->ty == Tfunction)
collectUnitTests(sds->members, uniqueUnitTests, exps);
}
TupleExp *te= new TupleExp(e->loc, exps);
- return semantic(te, sc);
+ return expressionSemantic(te, sc);
}
else if (e->ident == Id::getVirtualIndex)
{
e->error("`getTargetInfo` key `\"%s\"` not supported by this implementation", se->toPtr());
return new ErrorExp();
}
- return semantic(r, sc);
+ return expressionSemantic(r, sc);
}
else if (e->ident == Id::getLocation)
{
(*exps)[1] = new IntegerExp(e->loc, s->loc.linnum, Type::tint32);
(*exps)[2] = new IntegerExp(e->loc, s->loc.charnum, Type::tint32);
TupleExp *tup = new TupleExp(e->loc, exps);
- return semantic(tup, sc);
+ return expressionSemantic(tup, sc);
}
if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
- e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub);
+ e->error("unrecognized trait `%s`, did you mean `%s`?", e->ident->toChars(), sub);
else
- e->error("unrecognized trait '%s'", e->ident->toChars());
+ e->error("unrecognized trait `%s`", e->ident->toChars());
return new ErrorExp();
e->error("wrong number of arguments %d", (int)dim);
/* 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.
* http://www.boost.org/LICENSE_1_0.txt
*/
+#include "root/dsystem.h"
+#include "root/checkedint.h"
+
#include "mtype.h"
+#include "aggregate.h"
+#include "enum.h"
+#include "errors.h"
#include "expression.h"
+#include "hdrgen.h"
+#include "id.h"
+#include "init.h"
+#include "scope.h"
+#include "target.h"
#include "template.h"
+#include "visitor.h"
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+char *MODtoChars(MOD mod);
class TypeToExpressionVisitor : public Visitor
{
}
return e;
}
+
+/**************************
+ * This evaluates exp while setting length to be the number
+ * of elements in the tuple t.
+ */
+static Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
+{
+ if (t->ty == Ttuple)
+ {
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+
+ sc = sc->startCTFE();
+ exp = expressionSemantic(exp, sc);
+ sc = sc->endCTFE();
+
+ sc->pop();
+ }
+ else
+ {
+ sc = sc->startCTFE();
+ exp = expressionSemantic(exp, sc);
+ sc = sc->endCTFE();
+ }
+
+ return exp;
+}
+
+static Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
+{
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+
+ sc = sc->startCTFE();
+ exp = expressionSemantic(exp, sc);
+ sc = sc->endCTFE();
+
+ sc->pop();
+ return exp;
+}
+
+/******************************************
+ * Perform semantic analysis on a type.
+ * Params:
+ * type = Type AST node
+ * loc = the location of the type
+ * sc = context
+ * Returns:
+ * `Type` with completed semantic analysis, `Terror` if errors
+ * were encountered
+ */
+Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
+{
+ class TypeSemanticVisitor : public Visitor
+ {
+ public:
+ Loc loc;
+ Scope *sc;
+ Type *result;
+
+ TypeSemanticVisitor(const Loc &loc, Scope *sc)
+ {
+ this->loc = loc;
+ this->sc = sc;
+ this->result = NULL;
+ }
+
+ private:
+ void error()
+ {
+ result = Type::terror;
+ }
+
+ public:
+ void visit(Type *t)
+ {
+ if (t->ty == Tint128 || t->ty == Tuns128)
+ {
+ ::error(loc, "cent and ucent types not implemented");
+ return error();
+ }
+
+ result = t->merge();
+ }
+
+ void visit(TypeVector *mtype)
+ {
+ unsigned int errors = global.errors;
+ mtype->basetype = typeSemantic(mtype->basetype, loc, sc);
+ if (errors != global.errors)
+ return error();
+ mtype->basetype = mtype->basetype->toBasetype()->mutableOf();
+ if (mtype->basetype->ty != Tsarray)
+ {
+ ::error(loc, "T in __vector(T) must be a static array, not %s", mtype->basetype->toChars());
+ return error();
+ }
+ TypeSArray *t = (TypeSArray *)mtype->basetype;
+ int sz = (int)t->size(loc);
+ switch (target.isVectorTypeSupported(sz, t->nextOf()))
+ {
+ case 0: // valid
+ break;
+ case 1: // no support at all
+ ::error(loc, "SIMD vector types not supported on this platform");
+ return error();
+ case 2: // invalid base type
+ ::error(loc, "vector type %s is not supported on this platform", mtype->toChars());
+ return error();
+ case 3: // invalid size
+ ::error(loc, "%d byte vector type %s is not supported on this platform", sz, mtype->toChars());
+ return error();
+ default:
+ assert(0);
+ }
+ result = mtype->merge();
+ }
+
+ void visit(TypeSArray *mtype)
+ {
+ //printf("TypeSArray::semantic() %s\n", mtype->toChars());
+
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+ mtype->next->resolve(loc, sc, &e, &t, &s);
+
+ if (mtype->dim && s && s->isTupleDeclaration())
+ {
+ TupleDeclaration *sd = s->isTupleDeclaration();
+
+ mtype->dim = semanticLength(sc, sd, mtype->dim);
+ mtype->dim = mtype->dim->ctfeInterpret();
+ if(mtype->dim->op == TOKerror)
+ return error();
+
+ uinteger_t d = mtype->dim->toUInteger();
+ if (d >= sd->objects->length)
+ {
+ ::error(loc, "tuple index %llu exceeds %llu", (unsigned long long)d, (unsigned long long)sd->objects->length);
+ return error();
+ }
+
+ RootObject *o = (*sd->objects)[(size_t)d];
+ if (o->dyncast() != DYNCAST_TYPE)
+ {
+ ::error(loc, "%s is not a type", mtype->toChars());
+ return error();
+ }
+ result = ((Type *)o)->addMod(mtype->mod);
+ return;
+ }
+
+ if (t && t->ty == Terror)
+ return error();
+
+ Type *tn = typeSemantic(mtype->next, loc, sc);
+ if (tn->ty == Terror)
+ return error();
+
+ Type *tbn = tn->toBasetype();
+ if (mtype->dim)
+ {
+ unsigned int errors = global.errors;
+ mtype->dim = semanticLength(sc, tbn, mtype->dim);
+ if (errors != global.errors)
+ return error();
+
+ mtype->dim = mtype->dim->optimize(WANTvalue);
+ mtype->dim = mtype->dim->ctfeInterpret();
+ if (mtype->dim->op == TOKerror)
+ return error();
+ errors = global.errors;
+ dinteger_t d1 = mtype->dim->toInteger();
+ if (errors != global.errors)
+ return error();
+
+ mtype->dim = mtype->dim->implicitCastTo(sc, Type::tsize_t);
+ mtype->dim = mtype->dim->optimize(WANTvalue);
+ if (mtype->dim->op == TOKerror)
+ return error();
+ errors = global.errors;
+ dinteger_t d2 = mtype->dim->toInteger();
+ if (errors != global.errors)
+ return error();
+
+ if (mtype->dim->op == TOKerror)
+ return error();
+
+ if (d1 != d2)
+ {
+ Loverflow:
+ ::error(loc, "%s size %llu * %llu exceeds 0x%llx size limit for static array",
+ mtype->toChars(), (unsigned long long)tbn->size(loc), (unsigned long long)d1, target.maxStaticDataSize);
+ return error();
+ }
+
+ Type *tbx = tbn->baseElemOf();
+ if ((tbx->ty == Tstruct && !((TypeStruct *)tbx)->sym->members) ||
+ (tbx->ty == Tenum && !((TypeEnum *)tbx)->sym->members))
+ {
+ /* To avoid meaningless error message, skip the total size limit check
+ * when the bottom of element type is opaque.
+ */
+ }
+ else if (tbn->isTypeBasic() ||
+ tbn->ty == Tpointer ||
+ tbn->ty == Tarray ||
+ tbn->ty == Tsarray ||
+ tbn->ty == Taarray ||
+ (tbn->ty == Tstruct && (((TypeStruct *)tbn)->sym->sizeok == SIZEOKdone)) ||
+ tbn->ty == Tclass)
+ {
+ /* Only do this for types that don't need to have semantic()
+ * run on them for the size, since they may be forward referenced.
+ */
+ bool overflow = false;
+ if (mulu(tbn->size(loc), d2, overflow) >= target.maxStaticDataSize || overflow)
+ goto Loverflow;
+ }
+ }
+ switch (tbn->ty)
+ {
+ case Ttuple:
+ {
+ // Index the tuple to get the type
+ assert(mtype->dim);
+ TypeTuple *tt = (TypeTuple *)tbn;
+ uinteger_t d = mtype->dim->toUInteger();
+ if (d >= tt->arguments->length)
+ {
+ ::error(loc, "tuple index %llu exceeds %llu", (unsigned long long)d, (unsigned long long)tt->arguments->length);
+ return error();
+ }
+ Type *telem = (*tt->arguments)[(size_t)d]->type;
+ result = telem->addMod(mtype->mod);
+ return;
+ }
+ case Tfunction:
+ case Tnone:
+ ::error(loc, "cannot have array of %s", tbn->toChars());
+ return error();
+ default:
+ break;
+ }
+ if (tbn->isscope())
+ {
+ ::error(loc, "cannot have array of scope %s", tbn->toChars());
+ return error();
+ }
+
+ /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
+ * and const(T)[3] become const(T[3])
+ */
+ mtype->next = tn;
+ mtype->transitive();
+ result = mtype->addMod(tn->mod)->merge();
+ }
+
+ void visit(TypeDArray *mtype)
+ {
+ Type *tn = typeSemantic(mtype->next, loc,sc);
+ Type *tbn = tn->toBasetype();
+ switch (tbn->ty)
+ {
+ case Ttuple:
+ result = tbn;
+ return;
+ case Tfunction:
+ case Tnone:
+ ::error(loc, "cannot have array of %s", tbn->toChars());
+ return error();
+ case Terror:
+ return error();
+ default:
+ break;
+ }
+ if (tn->isscope())
+ {
+ ::error(loc, "cannot have array of scope %s", tn->toChars());
+ return error();
+ }
+ mtype->next = tn;
+ mtype->transitive();
+ result = mtype->merge();
+ }
+
+ void visit(TypeAArray *mtype)
+ {
+ //printf("TypeAArray::semantic() %s index->ty = %d\n", mtype->toChars(), mtype->index->ty);
+ if (mtype->deco)
+ {
+ result = mtype;
+ return;
+ }
+
+ mtype->loc = loc;
+ mtype->sc = sc;
+ if (sc)
+ sc->setNoFree();
+
+ // Deal with the case where we thought the index was a type, but
+ // in reality it was an expression.
+ if (mtype->index->ty == Tident || mtype->index->ty == Tinstance || mtype->index->ty == Tsarray ||
+ mtype->index->ty == Ttypeof || mtype->index->ty == Treturn)
+ {
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+
+ mtype->index->resolve(loc, sc, &e, &t, &s);
+ if (e)
+ {
+ // It was an expression -
+ // Rewrite as a static array
+ TypeSArray *tsa = new TypeSArray(mtype->next, e);
+ result = typeSemantic(tsa, loc, sc);
+ return;
+ }
+ else if (t)
+ mtype->index = typeSemantic(t, loc, sc);
+ else
+ {
+ mtype->index->error(loc, "index is not a type or an expression");
+ return error();
+ }
+ }
+ else
+ mtype->index = typeSemantic(mtype->index, loc,sc);
+ mtype->index = mtype->index->merge2();
+
+ if (mtype->index->nextOf() && !mtype->index->nextOf()->isImmutable())
+ {
+ mtype->index = mtype->index->constOf()->mutableOf();
+ }
+
+ switch (mtype->index->toBasetype()->ty)
+ {
+ case Tfunction:
+ case Tvoid:
+ case Tnone:
+ case Ttuple:
+ ::error(loc, "cannot have associative array key of %s", mtype->index->toBasetype()->toChars());
+ /* fall through */
+ case Terror:
+ return error();
+ default:
+ break;
+ }
+ Type *tbase = mtype->index->baseElemOf();
+ while (tbase->ty == Tarray)
+ tbase = tbase->nextOf()->baseElemOf();
+ if (tbase->ty == Tstruct)
+ {
+ /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
+ */
+ StructDeclaration *sd = ((TypeStruct *)tbase)->sym;
+ if (sd->semanticRun < PASSsemanticdone)
+ dsymbolSemantic(sd, NULL);
+
+ // duplicate a part of StructDeclaration::semanticTypeInfoMembers
+ //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", mtype->toChars(), sd->xeq, sd->xerreq, sd->xhash);
+ if (sd->xeq &&
+ sd->xeq->_scope &&
+ sd->xeq->semanticRun < PASSsemantic3done)
+ {
+ unsigned errors = global.startGagging();
+ semantic3(sd->xeq, sd->xeq->_scope);
+ if (global.endGagging(errors))
+ sd->xeq = sd->xerreq;
+ }
+
+ const char *s = (mtype->index->toBasetype()->ty != Tstruct) ? "bottom of " : "";
+ if (!sd->xeq)
+ {
+ // If sd->xhash != NULL:
+ // sd or its fields have user-defined toHash.
+ // AA assumes that its result is consistent with bitwise equality.
+ // else:
+ // bitwise equality & hashing
+ }
+ else if (sd->xeq == sd->xerreq)
+ {
+ if (search_function(sd, Id::eq))
+ {
+ ::error(loc, "%sAA key type %s does not have `bool opEquals(ref const %s) const`",
+ s, sd->toChars(), sd->toChars());
+ }
+ else
+ {
+ ::error(loc, "%sAA key type %s does not support const equality",
+ s, sd->toChars());
+ }
+ return error();
+ }
+ else if (!sd->xhash)
+ {
+ if (search_function(sd, Id::eq))
+ {
+ ::error(loc, "%sAA key type %s should have `size_t toHash() const nothrow @safe` if opEquals defined",
+ s, sd->toChars());
+ }
+ else
+ {
+ ::error(loc, "%sAA key type %s supports const equality but doesn't support const hashing",
+ s, sd->toChars());
+ }
+ return error();
+ }
+ else
+ {
+ // defined equality & hashing
+ assert(sd->xeq && sd->xhash);
+
+ /* xeq and xhash may be implicitly defined by compiler. For example:
+ * struct S { int[] arr; }
+ * With 'arr' field equality and hashing, compiler will implicitly
+ * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
+ */
+ }
+ }
+ else if (tbase->ty == Tclass && !((TypeClass *)tbase)->sym->isInterfaceDeclaration())
+ {
+ ClassDeclaration *cd = ((TypeClass *)tbase)->sym;
+ if (cd->semanticRun < PASSsemanticdone)
+ dsymbolSemantic(cd, NULL);
+
+ if (!ClassDeclaration::object)
+ {
+ ::error(Loc(), "missing or corrupt object.d");
+ fatal();
+ }
+
+ static FuncDeclaration *feq = NULL;
+ static FuncDeclaration *fcmp = NULL;
+ static FuncDeclaration *fhash = NULL;
+ if (!feq) feq = search_function(ClassDeclaration::object, Id::eq)->isFuncDeclaration();
+ if (!fcmp) fcmp = search_function(ClassDeclaration::object, Id::cmp)->isFuncDeclaration();
+ if (!fhash) fhash = search_function(ClassDeclaration::object, Id::tohash)->isFuncDeclaration();
+ assert(fcmp && feq && fhash);
+
+ if (feq->vtblIndex < (int)cd->vtbl.length && cd->vtbl[feq ->vtblIndex] == feq)
+ {
+ if (fcmp->vtblIndex < (int)cd->vtbl.length && cd->vtbl[fcmp->vtblIndex] != fcmp)
+ {
+ const char *s = (mtype->index->toBasetype()->ty != Tclass) ? "bottom of " : "";
+ ::error(loc, "%sAA key type %s now requires equality rather than comparison",
+ s, cd->toChars());
+ errorSupplemental(loc, "Please override Object.opEquals and toHash.");
+ }
+ }
+ }
+ mtype->next = typeSemantic(mtype->next, loc,sc)->merge2();
+ mtype->transitive();
+
+ switch (mtype->next->toBasetype()->ty)
+ {
+ case Tfunction:
+ case Tvoid:
+ case Tnone:
+ case Ttuple:
+ ::error(loc, "cannot have associative array of %s", mtype->next->toChars());
+ /* fall through */
+ case Terror:
+ return error();
+ }
+ if (mtype->next->isscope())
+ {
+ ::error(loc, "cannot have array of scope %s", mtype->next->toChars());
+ return error();
+ }
+ result = mtype->merge();
+ }
+
+ void visit(TypePointer *mtype)
+ {
+ //printf("TypePointer::semantic() %s\n", mtype->toChars());
+ if (mtype->deco)
+ {
+ result = mtype;
+ return;
+ }
+ Type *n = typeSemantic(mtype->next, loc, sc);
+ switch (n->toBasetype()->ty)
+ {
+ case Ttuple:
+ ::error(loc, "cannot have pointer to %s", n->toChars());
+ /* fall through */
+ case Terror:
+ return error();
+ default:
+ break;
+ }
+ if (n != mtype->next)
+ {
+ mtype->deco = NULL;
+ }
+ mtype->next = n;
+ if (mtype->next->ty != Tfunction)
+ {
+ mtype->transitive();
+ result = mtype->merge();
+ return;
+ }
+ mtype->deco = mtype->merge()->deco;
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ result = mtype;
+ }
+
+ void visit(TypeReference *mtype)
+ {
+ //printf("TypeReference::semantic()\n");
+ Type *n = typeSemantic(mtype->next, loc, sc);
+ if (n != mtype->next)
+ mtype->deco = NULL;
+ mtype->next = n;
+ mtype->transitive();
+ result = mtype->merge();
+ }
+
+
+ void visit(TypeFunction *mtype)
+ {
+ if (mtype->deco) // if semantic() already run
+ {
+ //printf("already done\n");
+ result = mtype;
+ return;
+ }
+ //printf("TypeFunction::semantic() this = %p\n", this);
+ //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", mtype->toChars(), sc->stc, mtype->fargs);
+
+ bool errors = false;
+
+ if (mtype->inuse > global.recursionLimit)
+ {
+ mtype->inuse = 0;
+ ::error(loc, "recursive type");
+ return error();
+ }
+
+ /* Copy in order to not mess up original.
+ * This can produce redundant copies if inferring return type,
+ * as semantic() will get called again on this.
+ */
+ TypeFunction *tf = mtype->copy()->toTypeFunction();
+ if (mtype->parameterList.parameters)
+ {
+ tf->parameterList.parameters = mtype->parameterList.parameters->copy();
+ for (size_t i = 0; i < mtype->parameterList.parameters->length; i++)
+ {
+ void *pp = mem.xmalloc(sizeof(Parameter));
+ Parameter *p = (Parameter *)memcpy(pp, (void *)(*mtype->parameterList.parameters)[i],
+ sizeof(Parameter));
+ (*tf->parameterList.parameters)[i] = p;
+ }
+ }
+
+ if (sc->stc & STCpure)
+ tf->purity = PUREfwdref;
+ if (sc->stc & STCnothrow)
+ tf->isnothrow = true;
+ if (sc->stc & STCnogc)
+ tf->isnogc = true;
+ if (sc->stc & STCref)
+ tf->isref = true;
+ if (sc->stc & STCreturn)
+ tf->isreturn = true;
+ if (sc->stc & STCscope)
+ tf->isscope = true;
+ if (sc->stc & STCscopeinferred)
+ tf->isscopeinferred = true;
+ //if ((sc->stc & (STCreturn | STCref)) == STCreturn)
+ // tf->isscope = true; // return by itself means 'return scope'
+
+ if (tf->trust == TRUSTdefault)
+ {
+ if (sc->stc & STCsafe)
+ tf->trust = TRUSTsafe;
+ if (sc->stc & STCsystem)
+ tf->trust = TRUSTsystem;
+ if (sc->stc & STCtrusted)
+ tf->trust = TRUSTtrusted;
+ }
+
+ if (sc->stc & STCproperty)
+ tf->isproperty = true;
+
+ tf->linkage = sc->linkage;
+ bool wildreturn = false;
+ if (tf->next)
+ {
+ sc = sc->push();
+ sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
+ tf->next = typeSemantic(tf->next, loc, sc);
+ sc = sc->pop();
+ errors |= tf->checkRetType(loc);
+ if (tf->next->isscope() && !(sc->flags & SCOPEctor))
+ {
+ ::error(loc, "functions cannot return scope %s", tf->next->toChars());
+ errors = true;
+ }
+ if (tf->next->hasWild())
+ wildreturn = true;
+
+ if (tf->isreturn && !tf->isref && !tf->next->hasPointers())
+ {
+ ::error(loc, "function type `%s` has `return` but does not return any indirections", tf->toChars());
+ }
+ }
+
+ unsigned char wildparams = 0;
+ if (tf->parameterList.parameters)
+ {
+ /* Create a scope for evaluating the default arguments for the parameters
+ */
+ Scope *argsc = sc->push();
+ argsc->stc = 0; // don't inherit storage class
+ argsc->protection = Prot(Prot::public_);
+ argsc->func = NULL;
+
+ size_t dim = tf->parameterList.length();
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam = tf->parameterList[i];
+ mtype->inuse++;
+ fparam->type = typeSemantic(fparam->type, loc, argsc);
+ mtype->inuse--;
+
+ if (fparam->type->ty == Terror)
+ {
+ errors = true;
+ continue;
+ }
+
+ fparam->type = fparam->type->addStorageClass(fparam->storageClass);
+
+ if (fparam->storageClass & (STCauto | STCalias | STCstatic))
+ {
+ if (!fparam->type)
+ continue;
+ }
+
+ Type *t = fparam->type->toBasetype();
+
+ if (t->ty == Tfunction)
+ {
+ ::error(loc, "cannot have parameter of function type %s", fparam->type->toChars());
+ errors = true;
+ }
+ else if (!(fparam->storageClass & (STCref | STCout)) &&
+ (t->ty == Tstruct || t->ty == Tsarray || t->ty == Tenum))
+ {
+ Type *tb2 = t->baseElemOf();
+ if ((tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members) ||
+ (tb2->ty == Tenum && !((TypeEnum *)tb2)->sym->memtype))
+ {
+ ::error(loc, "cannot have parameter of opaque type %s by value", fparam->type->toChars());
+ errors = true;
+ }
+ }
+ else if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
+ {
+ ::error(loc, "cannot have parameter of type %s", fparam->type->toChars());
+ errors = true;
+ }
+
+ if ((fparam->storageClass & (STCref | STCwild)) == (STCref | STCwild))
+ {
+ // 'ref inout' implies 'return'
+ fparam->storageClass |= STCreturn;
+ }
+
+ if (fparam->storageClass & STCreturn)
+ {
+ if (fparam->storageClass & (STCref | STCout))
+ {
+ // Disabled for the moment awaiting improvement to allow return by ref
+ // to be transformed into return by scope.
+ if (0 && !tf->isref)
+ {
+ StorageClass stc = fparam->storageClass & (STCref | STCout);
+ ::error(loc, "parameter %s is `return %s` but function does not return by ref",
+ fparam->ident ? fparam->ident->toChars() : "",
+ stcToChars(stc));
+ errors = true;
+ }
+ }
+ else
+ {
+ fparam->storageClass |= STCscope; // 'return' implies 'scope'
+ if (tf->isref)
+ {
+ }
+ else if (!tf->isref && tf->next && !tf->next->hasPointers())
+ {
+ ::error(loc, "parameter %s is `return` but function does not return any indirections",
+ fparam->ident ? fparam->ident->toChars() : "");
+ errors = true;
+ }
+ }
+ }
+
+ if (fparam->storageClass & (STCref | STClazy))
+ {
+ }
+ else if (fparam->storageClass & STCout)
+ {
+ if (unsigned char m = fparam->type->mod & (MODimmutable | MODconst | MODwild))
+ {
+ ::error(loc, "cannot have %s out parameter of type %s", MODtoChars(m), t->toChars());
+ errors = true;
+ }
+ else
+ {
+ Type *tv = t;
+ while (tv->ty == Tsarray)
+ tv = tv->nextOf()->toBasetype();
+ if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->noDefaultCtor)
+ {
+ ::error(loc, "cannot have out parameter of type %s because the default construction is disabled",
+ fparam->type->toChars());
+ errors = true;
+ }
+ }
+ }
+
+ if (fparam->storageClass & STCscope && !fparam->type->hasPointers() && fparam->type->ty != Ttuple)
+ {
+ fparam->storageClass &= ~STCscope;
+ if (!(fparam->storageClass & STCref))
+ fparam->storageClass &= ~STCreturn;
+ }
+
+ if (t->hasWild())
+ {
+ wildparams |= 1;
+ //if (tf->next && !wildreturn)
+ // ::error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
+ }
+
+ if (fparam->defaultArg)
+ {
+ Expression *e = fparam->defaultArg;
+ if (fparam->storageClass & (STCref | STCout))
+ {
+ e = expressionSemantic(e, argsc);
+ e = resolveProperties(argsc, e);
+ }
+ else
+ {
+ e = inferType(e, fparam->type);
+ Initializer *iz = new ExpInitializer(e->loc, e);
+ iz = initializerSemantic(iz, argsc, fparam->type, INITnointerpret);
+ e = initializerToExpression(iz);
+ }
+ if (e->op == TOKfunction) // see Bugzilla 4820
+ {
+ FuncExp *fe = (FuncExp *)e;
+ // Replace function literal with a function symbol,
+ // since default arg expression must be copied when used
+ // and copying the literal itself is wrong.
+ e = new VarExp(e->loc, fe->fd, false);
+ e = new AddrExp(e->loc, e);
+ e = expressionSemantic(e, argsc);
+ }
+ e = e->implicitCastTo(argsc, fparam->type);
+
+ // default arg must be an lvalue
+ if (fparam->storageClass & (STCout | STCref))
+ e = e->toLvalue(argsc, e);
+
+ fparam->defaultArg = e;
+ if (e->op == TOKerror)
+ errors = true;
+ }
+
+ /* If fparam after semantic() turns out to be a tuple, the number of parameters may
+ * change.
+ */
+ if (t->ty == Ttuple)
+ {
+ /* TypeFunction::parameter also is used as the storage of
+ * Parameter objects for FuncDeclaration. So we should copy
+ * the elements of TypeTuple::arguments to avoid unintended
+ * sharing of Parameter object among other functions.
+ */
+ TypeTuple *tt = (TypeTuple *)t;
+ if (tt->arguments && tt->arguments->length)
+ {
+ /* Propagate additional storage class from tuple parameters to their
+ * element-parameters.
+ * Make a copy, as original may be referenced elsewhere.
+ */
+ size_t tdim = tt->arguments->length;
+ Parameters *newparams = new Parameters();
+ newparams->setDim(tdim);
+ for (size_t j = 0; j < tdim; j++)
+ {
+ Parameter *narg = (*tt->arguments)[j];
+
+ // Bugzilla 12744: If the storage classes of narg
+ // conflict with the ones in fparam, it's ignored.
+ StorageClass stc = fparam->storageClass | narg->storageClass;
+ StorageClass stc1 = fparam->storageClass & (STCref | STCout | STClazy);
+ StorageClass stc2 = narg->storageClass & (STCref | STCout | STClazy);
+ if (stc1 && stc2 && stc1 != stc2)
+ {
+ OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STCref) ? (fparam->storageClass & STCauto) : 0));
+ OutBuffer buf2; stcToBuffer(&buf2, stc2);
+
+ ::error(loc, "incompatible parameter storage classes `%s` and `%s`",
+ buf1.peekChars(), buf2.peekChars());
+ errors = true;
+ stc = stc1 | (stc & ~(STCref | STCout | STClazy));
+ }
+
+ (*newparams)[j] = new Parameter(
+ stc, narg->type, narg->ident, narg->defaultArg, narg->userAttribDecl);
+ }
+ fparam->type = new TypeTuple(newparams);
+ }
+ fparam->storageClass = 0;
+
+ /* Reset number of parameters, and back up one to do this fparam again,
+ * now that it is a tuple
+ */
+ dim = tf->parameterList.length();
+ i--;
+ continue;
+ }
+
+ /* Resolve "auto ref" storage class to be either ref or value,
+ * based on the argument matching the parameter
+ */
+ if (fparam->storageClass & STCauto)
+ {
+ if (mtype->fargs && i < mtype->fargs->length && (fparam->storageClass & STCref))
+ {
+ Expression *farg = (*mtype->fargs)[i];
+ if (farg->isLvalue())
+ ; // ref parameter
+ else
+ fparam->storageClass &= ~STCref; // value parameter
+ fparam->storageClass &= ~STCauto; // Bugzilla 14656
+ fparam->storageClass |= STCautoref;
+ }
+ else
+ {
+ ::error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
+ errors = true;
+ }
+ }
+
+ // Remove redundant storage classes for type, they are already applied
+ fparam->storageClass &= ~(STC_TYPECTOR | STCin);
+ }
+ argsc->pop();
+ }
+ if (tf->isWild())
+ wildparams |= 2;
+
+ if (wildreturn && !wildparams)
+ {
+ ::error(loc, "inout on return means inout must be on a parameter as well for %s", mtype->toChars());
+ errors = true;
+ }
+ tf->iswild = wildparams;
+
+ if (tf->isproperty && (tf->parameterList.varargs != VARARGnone || tf->parameterList.length() > 2))
+ {
+ ::error(loc, "properties can only have zero, one, or two parameter");
+ errors = true;
+ }
+
+ if (tf->parameterList.varargs == VARARGvariadic && tf->linkage != LINKd && tf->parameterList.length() == 0)
+ {
+ ::error(loc, "variadic functions with non-D linkage must have at least one parameter");
+ errors = true;
+ }
+
+ if (errors)
+ return error();
+
+ if (tf->next)
+ tf->deco = tf->merge()->deco;
+
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ result = tf;
+ }
+
+ void visit(TypeDelegate *mtype)
+ {
+ //printf("TypeDelegate::semantic() %s\n", mtype->toChars());
+ if (mtype->deco) // if semantic() already run
+ {
+ //printf("already done\n");
+ result = mtype;
+ return;
+ }
+ mtype->next = typeSemantic(mtype->next, loc,sc);
+ if (mtype->next->ty != Tfunction)
+ return error();
+
+ /* In order to deal with Bugzilla 4028, perhaps default arguments should
+ * be removed from next before the merge.
+ */
+
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ mtype->deco = mtype->merge()->deco;
+ result = mtype;
+ }
+
+ void visit(TypeTraits *mtype)
+ {
+ if (mtype->ty == Terror)
+ {
+ result = mtype;
+ return;
+ }
+
+ const int inAlias = (sc->flags & SCOPEalias) != 0;
+ if (mtype->exp->ident != Id::allMembers &&
+ mtype->exp->ident != Id::derivedMembers &&
+ mtype->exp->ident != Id::getMember &&
+ mtype->exp->ident != Id::parent &&
+ mtype->exp->ident != Id::child &&
+ mtype->exp->ident != Id::getOverloads &&
+ mtype->exp->ident != Id::getVirtualFunctions &&
+ mtype->exp->ident != Id::getVirtualMethods &&
+ mtype->exp->ident != Id::getAttributes &&
+ mtype->exp->ident != Id::getUnitTests &&
+ mtype->exp->ident != Id::getAliasThis)
+ {
+ static const char *ctxt[2] = {"as type", "in alias"};
+ ::error(loc, "trait `%s` is either invalid or not supported %s",
+ mtype->exp->ident->toChars(), ctxt[inAlias]);
+ mtype->ty = Terror;
+ result = mtype;
+ return;
+ }
+
+ if (Expression *e = semanticTraits(mtype->exp, sc))
+ {
+ switch (e->op)
+ {
+ case TOKdotvar:
+ mtype->sym = ((DotVarExp *)e)->var;
+ break;
+ case TOKvar:
+ mtype->sym = ((VarExp *)e)->var;
+ break;
+ case TOKfunction:
+ {
+ FuncExp *fe = (FuncExp *)e;
+ if (fe->td)
+ mtype->sym = fe->td;
+ else
+ mtype->sym = fe->fd;
+ break;
+ }
+ case TOKdottd:
+ mtype->sym = ((DotTemplateExp*)e)->td;
+ break;
+ case TOKdsymbol:
+ mtype->sym = ((DsymbolExp *)e)->s;
+ break;
+ case TOKtemplate:
+ mtype->sym = ((TemplateExp *)e)->td;
+ break;
+ case TOKscope:
+ mtype->sym = ((ScopeExp *)e)->sds;
+ break;
+ case TOKtuple:
+ {
+ TupleExp *te = e->toTupleExp();
+ Objects *elems = new Objects;
+ elems->setDim(te->exps->length);
+ for (size_t i = 0; i < elems->length; i++)
+ {
+ Expression *src = (*te->exps)[i];
+ switch (src->op)
+ {
+ case TOKtype:
+ (*elems)[i] = ((TypeExp *)src)->type;
+ break;
+ case TOKdottype:
+ (*elems)[i] = ((DotTypeExp *)src)->type;
+ break;
+ case TOKoverloadset:
+ (*elems)[i] = ((OverExp *)src)->type;
+ break;
+ default:
+ if (Dsymbol *sym = isDsymbol(src))
+ (*elems)[i] = sym;
+ else
+ (*elems)[i] = src;
+ }
+ }
+ TupleDeclaration *td = new TupleDeclaration(e->loc,
+ Identifier::generateId("__aliastup"), elems);
+ mtype->sym = td;
+ break;
+ }
+ case TOKdottype:
+ result = isType(((DotTypeExp *)e)->sym);
+ break;
+ case TOKtype:
+ result = ((TypeExp *)e)->type;
+ break;
+ case TOKoverloadset:
+ result = ((OverExp *)e)->type;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (result)
+ result = result->addMod(mtype->mod);
+ if (!inAlias && !result)
+ {
+ if (!global.errors)
+ ::error(loc, "`%s` does not give a valid type", mtype->toChars());
+ return error();
+ }
+ }
+
+ void visit(TypeIdentifier *mtype)
+ {
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+
+ //printf("TypeIdentifier::semantic(%s)\n", mtype->toChars());
+ mtype->resolve(loc, sc, &e, &t, &s);
+ if (t)
+ {
+ //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
+ t = t->addMod(mtype->mod);
+ }
+ else
+ {
+ if (s)
+ {
+ s->error(loc, "is used as a type");
+ //halt();
+ }
+ else
+ ::error(loc, "%s is used as a type", mtype->toChars());
+ return error();
+ }
+ //t->print();
+ result = t;
+ }
+
+ void visit(TypeInstance *mtype)
+ {
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+
+ //printf("TypeInstance::semantic(%p, %s)\n", this, mtype->toChars());
+ {
+ unsigned errors = global.errors;
+ mtype->resolve(loc, sc, &e, &t, &s);
+ // if we had an error evaluating the symbol, suppress further errors
+ if (!t && errors != global.errors)
+ return error();
+ }
+
+ if (!t)
+ {
+ if (!e && s && s->errors)
+ {
+ // if there was an error evaluating the symbol, it might actually
+ // be a type. Avoid misleading error messages.
+ ::error(loc, "%s had previous errors", mtype->toChars());
+ }
+ else
+ ::error(loc, "%s is used as a type", mtype->toChars());
+ return error();
+ }
+ result = t;
+ }
+
+ void visit(TypeTypeof *mtype)
+ {
+ //printf("TypeTypeof::semantic() %s\n", mtype->toChars());
+
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ mtype->resolve(loc, sc, &e, &t, &s);
+ if (s && (t = s->getType()) != NULL)
+ t = t->addMod(mtype->mod);
+ if (!t)
+ {
+ ::error(loc, "%s is used as a type", mtype->toChars());
+ return error();
+ }
+ result = t;
+ }
+
+ void visit(TypeReturn *mtype)
+ {
+ //printf("TypeReturn::semantic() %s\n", mtype->toChars());
+
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ mtype->resolve(loc, sc, &e, &t, &s);
+ if (s && (t = s->getType()) != NULL)
+ t = t->addMod(mtype->mod);
+ if (!t)
+ {
+ ::error(loc, "%s is used as a type", mtype->toChars());
+ return error();
+ }
+ result = t;
+ }
+
+ void visit(TypeEnum *mtype)
+ {
+ //printf("TypeEnum::semantic() %s\n", mtype->toChars());
+ result = mtype->deco ? mtype : mtype->merge();
+ }
+
+ void visit(TypeStruct *mtype)
+ {
+ //printf("TypeStruct::semantic('%s')\n", mtype->sym->toChars());
+ if (mtype->deco)
+ {
+ if (sc && sc->cppmangle != CPPMANGLEdefault)
+ {
+ if (mtype->cppmangle == CPPMANGLEdefault)
+ mtype->cppmangle = sc->cppmangle;
+ else
+ assert(mtype->cppmangle == sc->cppmangle);
+ }
+ result = mtype;
+ return;
+ }
+
+ /* Don't semantic for sym because it should be deferred until
+ * sizeof needed or its members accessed.
+ */
+ // instead, parent should be set correctly
+ assert(mtype->sym->parent);
+
+ if (mtype->sym->type->ty == Terror)
+ return error();
+ if (sc)
+ mtype->cppmangle = sc->cppmangle;
+ result = mtype->merge();
+ }
+
+ void visit(TypeClass *mtype)
+ {
+ //printf("TypeClass::semantic(%s)\n", mtype->sym->toChars());
+ if (mtype->deco)
+ {
+ if (sc && sc->cppmangle != CPPMANGLEdefault)
+ {
+ if (mtype->cppmangle == CPPMANGLEdefault)
+ mtype->cppmangle = sc->cppmangle;
+ else
+ assert(mtype->cppmangle == sc->cppmangle);
+ }
+ result = mtype;
+ return;
+ }
+
+ /* Don't semantic for sym because it should be deferred until
+ * sizeof needed or its members accessed.
+ */
+ // instead, parent should be set correctly
+ assert(mtype->sym->parent);
+
+ if (mtype->sym->type->ty == Terror)
+ return error();
+ if (sc)
+ mtype->cppmangle = sc->cppmangle;
+ result = mtype->merge();
+ }
+
+ void visit(TypeTuple *mtype)
+ {
+ //printf("TypeTuple::semantic(this = %p)\n", this);
+ //printf("TypeTuple::semantic() %p, %s\n", this, mtype->toChars());
+ if (!mtype->deco)
+ mtype->deco = mtype->merge()->deco;
+
+ /* Don't return merge(), because a tuple with one type has the
+ * same deco as that type.
+ */
+ result = mtype;
+ }
+
+ void visit(TypeSlice *mtype)
+ {
+ //printf("TypeSlice::semantic() %s\n", mtype->toChars());
+ Type *tn = typeSemantic(mtype->next, loc, sc);
+ //printf("next: %s\n", tn->toChars());
+
+ Type *tbn = tn->toBasetype();
+ if (tbn->ty != Ttuple)
+ {
+ ::error(loc, "can only slice tuple types, not %s", tbn->toChars());
+ return error();
+ }
+ TypeTuple *tt = (TypeTuple *)tbn;
+
+ mtype->lwr = semanticLength(sc, tbn, mtype->lwr);
+ mtype->lwr = mtype->lwr->ctfeInterpret();
+ uinteger_t i1 = mtype->lwr->toUInteger();
+
+ mtype->upr = semanticLength(sc, tbn, mtype->upr);
+ mtype->upr = mtype->upr->ctfeInterpret();
+ uinteger_t i2 = mtype->upr->toUInteger();
+
+ if (!(i1 <= i2 && i2 <= tt->arguments->length))
+ {
+ ::error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]",
+ (unsigned long long)i1, (unsigned long long)i2, (unsigned long long)tt->arguments->length);
+ return error();
+ }
+
+ mtype->next = tn;
+ mtype->transitive();
+
+ Parameters *args = new Parameters;
+ args->reserve((size_t)(i2 - i1));
+ for (size_t i = (size_t)i1; i < (size_t)i2; i++)
+ {
+ Parameter *arg = (*tt->arguments)[i];
+ args->push(arg);
+ }
+ Type *t = new TypeTuple(args);
+ result = typeSemantic(t, loc, sc);
+ }
+ };
+ TypeSemanticVisitor v(loc, sc);
+ type->accept(&v);
+ return v.result;
+}
/* Compiler implementation of the D programming language
- * Copyright (C) 2003-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2003-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.
/* Compiler implementation of the D programming language
- * Copyright (C) 2003-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2003-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.
/* 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.
/* 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.
const char *toChars();
void addMember(Scope *sc, ScopeDsymbol *sds);
- void semantic(Scope *sc);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
};
const char *toChars();
void addMember(Scope *sc, ScopeDsymbol *sds);
- void semantic(Scope *sc);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
};
/* Compiler implementation of the D programming language
- * Copyright (C) 2013-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2013-2021 by The D Language Foundation, All Rights Reserved
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
ClassDeclaration *tinfo = ClassDeclaration::create (loc, ident, NULL, NULL,
true);
tinfo->parent = object_module;
- tinfo->semantic (object_module->_scope);
+ dsymbolSemantic (tinfo, object_module->_scope);
tinfo->baseClass = base;
/* This is a compiler generated class, and shouldn't be mistaken for being
the type declared in the runtime library. */