aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/attrib.c
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2020-03-13 21:03:02 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2020-03-13 21:03:02 +0100
commit5b74dd0a2278365eb562d9d1999c3c11cddb733c (patch)
treed50cf33dd430febb733c654fc1ea60dc7a34609f /gcc/d/dmd/attrib.c
parentdb3fa3476e9e922ca3e283df03ebd14be7220b6e (diff)
downloadgcc-5b74dd0a2278365eb562d9d1999c3c11cddb733c.zip
gcc-5b74dd0a2278365eb562d9d1999c3c11cddb733c.tar.gz
gcc-5b74dd0a2278365eb562d9d1999c3c11cddb733c.tar.bz2
d/dmd: Merge upstream dmd e9420cfbf
1. Implement DIP 1010 - (Static foreach) Support for 'static foreach' has been added. 'static foreach' is a conditional compilation construct that is to 'foreach' what 'static if' is to 'if'. It is a convenient way to generate declarations and statements by iteration. import std.conv: to; static foreach(i; 0 .. 10) { // a 'static foreach' body does not introduce a nested scope // (similar to 'static if'). // The following mixin declaration is at module scope: // declares 10 variables x0, x1, ..., x9 mixin('enum x' ~ to!string(i) ~ ' = i;'); } import std.range: iota; // all aggregate types that can be iterated with a standard 'foreach' // loop are also supported by static foreach: static foreach(i; iota(10)) { // we access the declarations generated in the first 'static foreach' pragma(msg, "x", i, ": ", mixin(`x` ~ to!string(i))); static assert(mixin(`x` ~ to!string(i)) == i); } void main() { import std.conv: text; import std.typecons: tuple; import std.algorithm: map; import std.stdio: writeln; // 'static foreach' has both declaration and statement forms // (similar to 'static if'). static foreach(x; iota(3).map!(i => tuple(text("x", i), i))) { // generates three local variables x0, x1 and x2. mixin(text(`int `,x[0],` = x[1];`)); scope(exit) // this is within the scope of 'main' { writeln(mixin(x[0])); } } writeln(x0," ",x1," ",x2); // first runtime output } 2. Aliases can be created directly from a '__trait'. Aliases can be created directly from the traits that return symbol(s) or tuples. This includes 'getMember', 'allMembers', 'derivedMembers', 'parent', 'getOverloads', 'getVirtualFunctions', 'getVirtualMethods', 'getUnitTests', 'getAttributes' and finally 'getAliasThis'. Previously an 'AliasSeq' was necessary in order to alias their return. Now the grammar allows to write shorter declarations: struct Foo { static int a; } alias oldWay = AliasSeq!(__traits(getMember, Foo, "a"))[0]; alias newWay = __traits(getMember, Foo, "a"); To permit this it was more interesting to include '__trait' in the basic types rather than just changing the alias syntax. So additionally, wherever a type appears a '__trait' can be used, for example in a variable declaration: struct Foo { static struct Bar {} } const(__traits(getMember, Foo, "Bar")) fooBar; static assert(is(typeof(fooBar) == const(Foo.Bar))); 3. fix Issue 10100 - Identifiers with double underscores and allMembers The identifer whitelist has been converted into a blacklist of all possible internal D language declarations. Reviewed-on: https://github.com/dlang/dmd/pull/10791
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");