aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/attrib.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/attrib.c')
-rw-r--r--gcc/d/dmd/attrib.c189
1 files changed, 187 insertions, 2 deletions
diff --git a/gcc/d/dmd/attrib.c b/gcc/d/dmd/attrib.c
index 6cd715c..86485d2 100644
--- a/gcc/d/dmd/attrib.c
+++ b/gcc/d/dmd/attrib.c
@@ -31,6 +31,7 @@
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 ****************************/
@@ -42,6 +43,9 @@ AttribDeclaration::AttribDeclaration(Dsymbols *decl)
Dsymbols *AttribDeclaration::include(Scope *, ScopeDsymbol *)
{
+ if (errors)
+ return NULL;
+
return decl;
}
@@ -752,6 +756,7 @@ void AnonDeclaration::semantic(Scope *sc)
{
::error(loc, "%s can only be a part of an aggregate, not %s %s",
kind(), p->kind(), p->toChars());
+ errors = true;
return;
}
@@ -1219,6 +1224,10 @@ bool ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
Dsymbols *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sds)
{
//printf("ConditionalDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
+
+ if (errors)
+ return NULL;
+
assert(condition);
return condition->include(_scope ? _scope : sc, sds) ? decl : elsedecl;
}
@@ -1275,6 +1284,7 @@ StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
//printf("StaticIfDeclaration::StaticIfDeclaration()\n");
scopesym = NULL;
addisdone = false;
+ onStack = false;
}
Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
@@ -1293,12 +1303,17 @@ Dsymbols *StaticIfDeclaration::include(Scope *sc, ScopeDsymbol *)
{
//printf("StaticIfDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
+ if (errors || onStack)
+ return NULL;
+ onStack = true;
+ Dsymbols *d;
+
if (condition->inc == 0)
{
assert(scopesym); // addMember is already done
assert(_scope); // setScope is already done
- Dsymbols *d = ConditionalDeclaration::include(_scope, scopesym);
+ d = ConditionalDeclaration::include(_scope, scopesym);
if (d && !addisdone)
{
@@ -1318,11 +1333,14 @@ Dsymbols *StaticIfDeclaration::include(Scope *sc, ScopeDsymbol *)
addisdone = true;
}
+ onStack = false;
return d;
}
else
{
- return ConditionalDeclaration::include(sc, scopesym);
+ d = ConditionalDeclaration::include(sc, scopesym);
+ onStack = false;
+ return d;
}
}
@@ -1366,6 +1384,173 @@ const char *StaticIfDeclaration::kind() const
return "static if";
}
+/***************************** StaticForeachDeclaration ***********************/
+
+/* Static foreach at declaration scope, like:
+ * static foreach (i; [0, 1, 2]){ }
+ */
+
+StaticForeachDeclaration::StaticForeachDeclaration(StaticForeach *sfe, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ this->sfe = sfe;
+ this->scopesym = NULL;
+ this->onStack = false;
+ this->cached = false;
+ this->cache = NULL;
+}
+
+Dsymbol *StaticForeachDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new StaticForeachDeclaration(
+ sfe->syntaxCopy(),
+ Dsymbol::arraySyntaxCopy(decl));
+}
+
+bool StaticForeachDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+ // Required to support IFTI on a template that contains a
+ // `static foreach` declaration. `super.oneMember` calls
+ // include with a `null` scope. As `static foreach` requires
+ // the scope for expansion, `oneMember` can only return a
+ // precise result once `static foreach` has been expanded.
+ if (cached)
+ {
+ return AttribDeclaration::oneMember(ps, ident);
+ }
+ *ps = NULL; // a `static foreach` declaration may in general expand to multiple symbols
+ return false;
+}
+
+Dsymbols *StaticForeachDeclaration::include(Scope *, ScopeDsymbol *)
+{
+ if (errors || onStack)
+ return NULL;
+ if (cached)
+ {
+ assert(!onStack);
+ return cache;
+ }
+ onStack = true;
+
+ if (_scope)
+ {
+ staticForeachPrepare(sfe, _scope); // lower static foreach aggregate
+ }
+ if (!staticForeachReady(sfe))
+ {
+ onStack = false;
+ return NULL; // TODO: ok?
+ }
+
+ // expand static foreach
+ Dsymbols *d = makeTupleForeachStaticDecl(_scope, sfe->aggrfe, decl, sfe->needExpansion);
+ if (d) // process generated declarations
+ {
+ // Add members lazily.
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->addMember(_scope, scopesym);
+ }
+ // Set the member scopes lazily.
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->setScope(_scope);
+ }
+ }
+ onStack = false;
+ cached = true;
+ cache = d;
+ return d;
+}
+
+void StaticForeachDeclaration::addMember(Scope *, ScopeDsymbol *sds)
+{
+ // used only for caching the enclosing symbol
+ this->scopesym = sds;
+}
+
+void StaticForeachDeclaration::addComment(const utf8_t *)
+{
+ // do nothing
+ // change this to give semantics to documentation comments on static foreach declarations
+}
+
+void StaticForeachDeclaration::setScope(Scope *sc)
+{
+ // do not evaluate condition before semantic pass
+ // But do set the scope, in case we need it for forward referencing
+ Dsymbol::setScope(sc);
+}
+
+void StaticForeachDeclaration::importAll(Scope *)
+{
+ // do not evaluate aggregate before semantic pass
+}
+
+void StaticForeachDeclaration::semantic(Scope *sc)
+{
+ AttribDeclaration::semantic(sc);
+}
+
+const char *StaticForeachDeclaration::kind() const
+{
+ return "static foreach";
+}
+
+/***********************************************************
+ * Collection of declarations that stores foreach index variables in a
+ * local symbol table. Other symbols declared within are forwarded to
+ * another scope, like:
+ *
+ * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
+ * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STClocal
+ * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
+ * }
+ *
+ * static foreach (i; 0.. 10)
+ * {
+ * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
+ * }
+ *
+ * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
+ *
+ * A StaticForeachDeclaration generates one
+ * ForwardingAttribDeclaration for each expansion of its body. The
+ * AST of the ForwardingAttribDeclaration contains both the `static
+ * foreach` variables and the respective copy of the `static foreach`
+ * body. The functionality is achieved by using a
+ * ForwardingScopeDsymbol as the parent symbol for the generated
+ * declarations.
+ */
+
+ForwardingAttribDeclaration::ForwardingAttribDeclaration(Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ sym = new ForwardingScopeDsymbol(NULL);
+ sym->symtab = new DsymbolTable();
+}
+
+/**************************************
+ * Use the ForwardingScopeDsymbol as the parent symbol for members.
+ */
+Scope *ForwardingAttribDeclaration::newScope(Scope *sc)
+{
+ return sc->push(sym);
+}
+
+/***************************************
+ * Lazily initializes the scope to forward to.
+ */
+void ForwardingAttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+ parent = sym->parent = sym->forward = sds;
+ return AttribDeclaration::addMember(sc, sym);
+}
+
/***************************** CompileDeclaration *****************************/
// These are mixin declarations, like mixin("int x");