aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/semantic2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/semantic2.c')
-rw-r--r--gcc/d/dmd/semantic2.c410
1 files changed, 410 insertions, 0 deletions
diff --git a/gcc/d/dmd/semantic2.c b/gcc/d/dmd/semantic2.c
new file mode 100644
index 0000000..7bcf6ce
--- /dev/null
+++ b/gcc/d/dmd/semantic2.c
@@ -0,0 +1,410 @@
+
+/* 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);
+}