aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/semantic2.c
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2021-02-09 15:40:06 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2021-02-13 12:50:45 +0100
commita3b38b7781622babb5ca68c621367770a65012fa (patch)
tree32ba65cb98047efa6ed8f86b327903ce647c008f /gcc/d/dmd/semantic2.c
parent0f3a743b688f4845e1798eed9b2e2284e891da11 (diff)
downloadgcc-a3b38b7781622babb5ca68c621367770a65012fa.zip
gcc-a3b38b7781622babb5ca68c621367770a65012fa.tar.gz
gcc-a3b38b7781622babb5ca68c621367770a65012fa.tar.bz2
d: Merge upstream dmd 7132b3537
Splits out all semantic passes for Dsymbol, Type, and TemplateParameter nodes into Visitors in separate files, and the copyright years of all sources have been updated. Reviewed-on: https://github.com/dlang/dmd/pull/12190 gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 7132b3537. * Make-lang.in (D_FRONTEND_OBJS): Add d/dsymbolsem.o, d/semantic2.o, d/semantic3.o, and d/templateparamsem.o. * d-compiler.cc (Compiler::genCmain): Update calls to semantic entrypoint functions. * d-lang.cc (d_parse_file): Likewise. * typeinfo.cc (make_frontend_typeinfo): Likewise.
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);
+}