summaryrefslogtreecommitdiff
path: root/gcc/d
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
parentdb3fa3476e9e922ca3e283df03ebd14be7220b6e (diff)
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')
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/attrib.c189
-rw-r--r--gcc/d/dmd/attrib.h9
-rw-r--r--gcc/d/dmd/cond.c333
-rw-r--r--gcc/d/dmd/cond.h5
-rw-r--r--gcc/d/dmd/cppmangle.c2
-rw-r--r--gcc/d/dmd/declaration.c9
-rw-r--r--gcc/d/dmd/dinterpret.c4
-rw-r--r--gcc/d/dmd/dmangle.c1
-rw-r--r--gcc/d/dmd/dsymbol.c100
-rw-r--r--gcc/d/dmd/dsymbol.h2
-rw-r--r--gcc/d/dmd/expression.c10
-rw-r--r--gcc/d/dmd/expression.h2
-rw-r--r--gcc/d/dmd/expressionsem.c27
-rw-r--r--gcc/d/dmd/func.c4
-rw-r--r--gcc/d/dmd/hdrgen.c68
-rw-r--r--gcc/d/dmd/init.c2
-rw-r--r--gcc/d/dmd/intrange.c2
-rw-r--r--gcc/d/dmd/json.c4
-rw-r--r--gcc/d/dmd/mtype.c152
-rw-r--r--gcc/d/dmd/mtype.h18
-rw-r--r--gcc/d/dmd/parse.c304
-rw-r--r--gcc/d/dmd/parse.h3
-rw-r--r--gcc/d/dmd/scope.h3
-rw-r--r--gcc/d/dmd/statement.c120
-rw-r--r--gcc/d/dmd/statement.h9
-rw-r--r--gcc/d/dmd/statementsem.c581
-rw-r--r--gcc/d/dmd/traits.c34
-rw-r--r--gcc/d/dmd/visitor.h4
29 files changed, 1681 insertions, 322 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 578f3fc0309..b017c037d74 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-b37a537d36c2ac69afa505a3110e2328c9fc0114
+e9420cfbf5cd0cf9e6e398603e009ccc8e14d324
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/attrib.c b/gcc/d/dmd/attrib.c
index 6cd715ce08b..86485d27616 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");
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index d1f265a84b9..ccfcddadaca 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -191,6 +191,7 @@ class StaticIfDeclaration : public ConditionalDeclaration
public:
ScopeDsymbol *scopesym;
bool addisdone;
+ bool onStack;
StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
Dsymbol *syntaxCopy(Dsymbol *s);
@@ -203,14 +204,16 @@ public:
void accept(Visitor *v) { v->visit(this); }
};
-class StaticForeachDeclaration : public ConditionalDeclaration
+class StaticForeachDeclaration : public AttribDeclaration
{
public:
StaticForeach *sfe;
ScopeDsymbol *scopesym;
+ bool onStack;
bool cached;
Dsymbols *cache;
+ StaticForeachDeclaration(StaticForeach *sfe, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
bool oneMember(Dsymbol **ps, Identifier *ident);
Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
@@ -223,14 +226,16 @@ public:
void accept(Visitor *v) { v->visit(this); }
};
-class ForwardingAttribDeclaration : AttribDeclaration
+class ForwardingAttribDeclaration : public AttribDeclaration
{
public:
ForwardingScopeDsymbol *sym;
+ ForwardingAttribDeclaration(Dsymbols *decl);
Scope *newScope(Scope *sc);
void addMember(Scope *sc, ScopeDsymbol *sds);
ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
};
// Mixin declarations
diff --git a/gcc/d/dmd/cond.c b/gcc/d/dmd/cond.c
index 9d7df5fd240..c75399d3825 100644
--- a/gcc/d/dmd/cond.c
+++ b/gcc/d/dmd/cond.c
@@ -13,6 +13,7 @@
#include "mars.h"
#include "id.h"
#include "init.h"
+#include "aggregate.h"
#include "declaration.h"
#include "identifier.h"
#include "expression.h"
@@ -21,6 +22,7 @@
#include "template.h"
#include "mtype.h"
#include "scope.h"
+#include "statement.h"
#include "arraytypes.h"
#include "tokens.h"
@@ -53,6 +55,327 @@ Condition::Condition(Loc loc)
/* ============================================================ */
+StaticForeach::StaticForeach(Loc loc, ForeachStatement *aggrfe, ForeachRangeStatement *rangefe)
+{
+ assert(!!aggrfe ^ !!rangefe);
+ this->loc = loc;
+ this->aggrfe = aggrfe;
+ this->rangefe = rangefe;
+ this->needExpansion = false;
+}
+
+StaticForeach *StaticForeach::syntaxCopy()
+{
+ return new StaticForeach(
+ loc,
+ aggrfe ? (ForeachStatement *)aggrfe->syntaxCopy() : NULL,
+ rangefe ? (ForeachRangeStatement *)rangefe->syntaxCopy() : NULL
+ );
+}
+
+/*****************************************
+ * Turn an aggregate which is an array into an expression tuple
+ * of its elements. I.e., lower
+ * static foreach (x; [1, 2, 3, 4]) { ... }
+ * to
+ * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
+ */
+
+static void lowerArrayAggregate(StaticForeach *sfe, Scope *sc)
+{
+ Expression *aggr = sfe->aggrfe->aggr;
+ Expression *el = new ArrayLengthExp(aggr->loc, aggr);
+ sc = sc->startCTFE();
+ el = semantic(el, sc);
+ sc = sc->endCTFE();
+ el = el->optimize(WANTvalue);
+ el = el->ctfeInterpret();
+ if (el->op == TOKint64)
+ {
+ dinteger_t length = el->toInteger();
+ Expressions *es = new Expressions();
+ for (size_t i = 0; i < length; i++)
+ {
+ IntegerExp *index = new IntegerExp(sfe->loc, i, Type::tsize_t);
+ Expression *value = new IndexExp(aggr->loc, aggr, index);
+ es->push(value);
+ }
+ sfe->aggrfe->aggr = new TupleExp(aggr->loc, es);
+ sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc);
+ sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
+ }
+ else
+ {
+ sfe->aggrfe->aggr = new ErrorExp();
+ }
+}
+
+/*****************************************
+ * Wrap a statement into a function literal and call it.
+ *
+ * Params:
+ * loc = The source location.
+ * s = The statement.
+ * Returns:
+ * AST of the expression `(){ s; }()` with location loc.
+ */
+
+static Expression *wrapAndCall(Loc loc, Statement *s)
+{
+ TypeFunction *tf = new TypeFunction(new Parameters(), NULL, 0, LINKdefault, 0);
+ FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, loc, tf, TOKreserved, NULL);
+ fd->fbody = s;
+ FuncExp *fe = new FuncExp(loc, fd);
+ Expression *ce = new CallExp(loc, fe, new Expressions());
+ return ce;
+}
+
+/*****************************************
+ * Create a `foreach` statement from `aggrefe/rangefe` with given
+ * `foreach` variables and body `s`.
+ *
+ * Params:
+ * loc = The source location.
+ * parameters = The foreach variables.
+ * s = The `foreach` body.
+ * Returns:
+ * `foreach (parameters; aggregate) s;` or
+ * `foreach (parameters; lower .. upper) s;`
+ * Where aggregate/lower, upper are as for the current StaticForeach.
+ */
+
+static Statement *createForeach(StaticForeach *sfe, Loc loc, Parameters *parameters, Statement *s)
+{
+ if (sfe->aggrfe)
+ {
+ return new ForeachStatement(loc, sfe->aggrfe->op, parameters, sfe->aggrfe->aggr->syntaxCopy(), s, loc);
+ }
+ else
+ {
+ assert(sfe->rangefe && parameters->dim == 1);
+ return new ForeachRangeStatement(loc, sfe->rangefe->op, (*parameters)[0],
+ sfe->rangefe->lwr->syntaxCopy(),
+ sfe->rangefe->upr->syntaxCopy(), s, loc);
+ }
+}
+
+/*****************************************
+ * For a `static foreach` with multiple loop variables, the
+ * aggregate is lowered to an array of tuples. As D does not have
+ * built-in tuples, we need a suitable tuple type. This generates
+ * a `struct` that serves as the tuple type. This type is only
+ * used during CTFE and hence its typeinfo will not go to the
+ * object file.
+ *
+ * Params:
+ * loc = The source location.
+ * e = The expressions we wish to store in the tuple.
+ * sc = The current scope.
+ * Returns:
+ * A struct type of the form
+ * struct Tuple
+ * {
+ * typeof(AliasSeq!(e)) tuple;
+ * }
+ */
+
+static TypeStruct *createTupleType(Loc loc, Expressions *e)
+{ // TODO: move to druntime?
+ Identifier *sid = Identifier::generateId("Tuple");
+ StructDeclaration *sdecl = new StructDeclaration(loc, sid, false);
+ sdecl->storage_class |= STCstatic;
+ sdecl->members = new Dsymbols();
+ Identifier *fid = Identifier::idPool("tuple");
+ Type *ty = new TypeTypeof(loc, new TupleExp(loc, e));
+ sdecl->members->push(new VarDeclaration(loc, ty, fid, NULL));
+ TypeStruct *r = (TypeStruct *)sdecl->type;
+ r->vtinfo = TypeInfoStructDeclaration::create(r); // prevent typeinfo from going to object file
+ return r;
+}
+
+/*****************************************
+ * Create the AST for an instantiation of a suitable tuple type.
+ *
+ * Params:
+ * loc = The source location.
+ * type = A Tuple type, created with createTupleType.
+ * e = The expressions we wish to store in the tuple.
+ * Returns:
+ * An AST for the expression `Tuple(e)`.
+ */
+
+static Expression *createTuple(Loc loc, TypeStruct *type, Expressions *e)
+{ // TODO: move to druntime?
+ return new CallExp(loc, new TypeExp(loc, type), e);
+}
+
+/*****************************************
+ * Lower any aggregate that is not an array to an array using a
+ * regular foreach loop within CTFE. If there are multiple
+ * `static foreach` loop variables, an array of tuples is
+ * generated. In thise case, the field `needExpansion` is set to
+ * true to indicate that the static foreach loop expansion will
+ * need to expand the tuples into multiple variables.
+ *
+ * For example, `static foreach (x; range) { ... }` is lowered to:
+ *
+ * static foreach (x; {
+ * typeof({
+ * foreach (x; range) return x;
+ * }())[] __res;
+ * foreach (x; range) __res ~= x;
+ * return __res;
+ * }()) { ... }
+ *
+ * Finally, call `lowerArrayAggregate` to turn the produced
+ * array into an expression tuple.
+ *
+ * Params:
+ * sc = The current scope.
+ */
+
+static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc)
+{
+ size_t nvars = sfe->aggrfe ? sfe->aggrfe->parameters->dim : 1;
+ Loc aloc = sfe->aggrfe ? sfe->aggrfe->aggr->loc : sfe->rangefe->lwr->loc;
+ // We need three sets of foreach loop variables because the
+ // lowering contains three foreach loops.
+ Parameters *pparams[3] = {new Parameters(), new Parameters(), new Parameters()};
+ for (size_t i = 0; i < nvars; i++)
+ {
+ for (size_t j = 0; j < 3; j++)
+ {
+ Parameters *params = pparams[j];
+ Parameter *p = sfe->aggrfe ? (*sfe->aggrfe->parameters)[i] : sfe->rangefe->prm;
+ params->push(new Parameter(p->storageClass, p->type, p->ident, NULL));
+ }
+ }
+ Expression *res[2];
+ TypeStruct *tplty = NULL;
+ if (nvars == 1) // only one `static foreach` variable, generate identifiers.
+ {
+ for (size_t i = 0; i < 2; i++)
+ {
+ res[i] = new IdentifierExp(aloc, (*pparams[i])[0]->ident);
+ }
+ }
+ else // multiple `static foreach` variables, generate tuples.
+ {
+ for (size_t i = 0; i < 2; i++)
+ {
+ Expressions *e = new Expressions();
+ for (size_t j = 0; j < pparams[0]->dim; j++)
+ {
+ Parameter *p = (*pparams[i])[j];
+ e->push(new IdentifierExp(aloc, p->ident));
+ }
+ if (!tplty)
+ {
+ tplty = createTupleType(aloc, e);
+ }
+ res[i] = createTuple(aloc, tplty, e);
+ }
+ sfe->needExpansion = true; // need to expand the tuples later
+ }
+ // generate remaining code for the new aggregate which is an
+ // array (see documentation comment).
+ if (sfe->rangefe)
+ {
+ sc = sc->startCTFE();
+ sfe->rangefe->lwr = semantic(sfe->rangefe->lwr, sc);
+ sfe->rangefe->lwr = resolveProperties(sc, sfe->rangefe->lwr);
+ sfe->rangefe->upr = semantic(sfe->rangefe->upr, sc);
+ sfe->rangefe->upr = resolveProperties(sc, sfe->rangefe->upr);
+ sc = sc->endCTFE();
+ sfe->rangefe->lwr = sfe->rangefe->lwr->optimize(WANTvalue);
+ sfe->rangefe->lwr = sfe->rangefe->lwr->ctfeInterpret();
+ sfe->rangefe->upr = sfe->rangefe->upr->optimize(WANTvalue);
+ sfe->rangefe->upr = sfe->rangefe->upr->ctfeInterpret();
+ }
+ Statements *s1 = new Statements();
+ Statements *sfebody = new Statements();
+ if (tplty) sfebody->push(new ExpStatement(sfe->loc, tplty->sym));
+ sfebody->push(new ReturnStatement(aloc, res[0]));
+ s1->push(createForeach(sfe, aloc, pparams[0], new CompoundStatement(aloc, sfebody)));
+ s1->push(new ExpStatement(aloc, new AssertExp(aloc, new IntegerExp(aloc, 0, Type::tint32))));
+ Type *ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
+ Type *aty = ety->arrayOf();
+ Identifier *idres = Identifier::generateId("__res");
+ VarDeclaration *vard = new VarDeclaration(aloc, aty, idres, NULL);
+ Statements *s2 = new Statements();
+ s2->push(new ExpStatement(aloc, vard));
+ Expression *catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
+ s2->push(createForeach(sfe, aloc, pparams[1], new ExpStatement(aloc, catass)));
+ s2->push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
+ Expression *aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
+ sc = sc->startCTFE();
+ aggr = semantic(aggr, sc);
+ aggr = resolveProperties(sc, aggr);
+ sc = sc->endCTFE();
+ aggr = aggr->optimize(WANTvalue);
+ aggr = aggr->ctfeInterpret();
+
+ assert(!!sfe->aggrfe ^ !!sfe->rangefe);
+ sfe->aggrfe = new ForeachStatement(sfe->loc, TOKforeach, pparams[2], aggr,
+ sfe->aggrfe ? sfe->aggrfe->_body : sfe->rangefe->_body,
+ sfe->aggrfe ? sfe->aggrfe->endloc : sfe->rangefe->endloc);
+ sfe->rangefe = NULL;
+ lowerArrayAggregate(sfe, sc); // finally, turn generated array into expression tuple
+}
+
+/*****************************************
+ * Perform `static foreach` lowerings that are necessary in order
+ * to finally expand the `static foreach` using
+ * `ddmd.statementsem.makeTupleForeach`.
+ */
+
+void staticForeachPrepare(StaticForeach *sfe, Scope *sc)
+{
+ assert(sc);
+ if (sfe->aggrfe)
+ {
+ sc = sc->startCTFE();
+ sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc);
+ sc = sc->endCTFE();
+ sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
+ Type *tab = sfe->aggrfe->aggr->type->toBasetype();
+ if (tab->ty != Ttuple)
+ {
+ sfe->aggrfe->aggr = sfe->aggrfe->aggr->ctfeInterpret();
+ }
+ }
+
+ if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Terror)
+ {
+ return;
+ }
+
+ if (!staticForeachReady(sfe))
+ {
+ if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Tarray)
+ {
+ lowerArrayAggregate(sfe, sc);
+ }
+ else
+ {
+ lowerNonArrayAggregate(sfe, sc);
+ }
+ }
+}
+
+/*****************************************
+ * Returns:
+ * `true` iff ready to call `ddmd.statementsem.makeTupleForeach`.
+ */
+
+bool staticForeachReady(StaticForeach *sfe)
+{
+ return sfe->aggrfe && sfe->aggrfe->aggr && sfe->aggrfe->aggr->type &&
+ sfe->aggrfe->aggr->type->toBasetype()->ty == Ttuple;
+}
+
+/* ============================================================ */
+
DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
: Condition(Loc())
{
@@ -324,7 +647,6 @@ StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
: Condition(loc)
{
this->exp = exp;
- this->nest = 0;
}
Condition *StaticIfCondition::syntaxCopy()
@@ -336,13 +658,6 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
{
if (inc == 0)
{
- if (exp->op == TOKerror || nest > 100)
- {
- error(loc, (nest > 1000) ? "unresolvable circular static if expression"
- : "error evaluating static if expression");
- goto Lerror;
- }
-
if (!sc)
{
error(loc, "static if conditional cannot be at global scope");
@@ -350,14 +665,12 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
return 0;
}
- ++nest;
sc = sc->push(sc->scopesym);
sc->sds = sds; // sds gets any addMember()
bool errors = false;
bool result = evalStaticCondition(sc, exp, exp, errors);
sc->pop();
- --nest;
// Prevent repeated condition evaluation.
// See: fail_compilation/fail7815.d
diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h
index 8e33b16a9da..576de8c26c2 100644
--- a/gcc/d/dmd/cond.h
+++ b/gcc/d/dmd/cond.h
@@ -53,9 +53,13 @@ public:
bool needExpansion;
+ StaticForeach(Loc loc, ForeachStatement *aggrfe, ForeachRangeStatement *rangefe);
StaticForeach *syntaxCopy();
};
+void staticForeachPrepare(StaticForeach *sfe, Scope *sc);
+bool staticForeachReady(StaticForeach *sfe);
+
class DVCondition : public Condition
{
public:
@@ -100,7 +104,6 @@ class StaticIfCondition : public Condition
{
public:
Expression *exp;
- int nest; // limit circular dependencies
StaticIfCondition(Loc loc, Expression *exp);
Condition *syntaxCopy();
diff --git a/gcc/d/dmd/cppmangle.c b/gcc/d/dmd/cppmangle.c
index 9b24fd2c2e4..6179bfd789e 100644
--- a/gcc/d/dmd/cppmangle.c
+++ b/gcc/d/dmd/cppmangle.c
@@ -261,7 +261,7 @@ class CppMangleVisitor : public Visitor
fatal();
}
}
- else if(tp->isTemplateThisParameter())
+ else if (tp->isTemplateThisParameter())
{
ti->error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o->toChars());
fatal();
diff --git a/gcc/d/dmd/declaration.c b/gcc/d/dmd/declaration.c
index 0018d9501f0..806e29d6907 100644
--- a/gcc/d/dmd/declaration.c
+++ b/gcc/d/dmd/declaration.c
@@ -340,6 +340,9 @@ void AliasDeclaration::semantic(Scope *sc)
void AliasDeclaration::aliasSemantic(Scope *sc)
{
//printf("AliasDeclaration::semantic() %s\n", toChars());
+ // TypeTraits needs to know if it's located in an AliasDeclaration
+ sc->flags |= SCOPEalias;
+
if (aliassym)
{
FuncDeclaration *fd = aliassym->isFuncLiteralDeclaration();
@@ -347,7 +350,10 @@ void AliasDeclaration::aliasSemantic(Scope *sc)
if (fd || (td && td->literal))
{
if (fd && fd->semanticRun >= PASSsemanticdone)
+ {
+ sc->flags &= ~SCOPEalias;
return;
+ }
Expression *e = new FuncExp(loc, aliassym);
e = ::semantic(e, sc);
@@ -361,11 +367,13 @@ void AliasDeclaration::aliasSemantic(Scope *sc)
aliassym = NULL;
type = Type::terror;
}
+ sc->flags &= ~SCOPEalias;
return;
}
if (aliassym->isTemplateInstance())
aliassym->semantic(sc);
+ sc->flags &= ~SCOPEalias;
return;
}
inuse = 1;
@@ -470,6 +478,7 @@ void AliasDeclaration::aliasSemantic(Scope *sc)
if (!overloadInsert(sx))
ScopeDsymbol::multiplyDefined(Loc(), sx, this);
}
+ sc->flags &= ~SCOPEalias;
}
bool AliasDeclaration::overloadInsert(Dsymbol *s)
diff --git a/gcc/d/dmd/dinterpret.c b/gcc/d/dmd/dinterpret.c
index a1658bbd051..61f5cdb0730 100644
--- a/gcc/d/dmd/dinterpret.c
+++ b/gcc/d/dmd/dinterpret.c
@@ -4649,6 +4649,10 @@ public:
result = getVarExp(e->loc, istate, ((SymbolExp *)ea)->var, ctfeNeedRvalue);
else if (ea->op == TOKaddress)
result = interpret(((AddrExp *)ea)->e1, istate);
+ // https://issues.dlang.org/show_bug.cgi?id=18871
+ // https://issues.dlang.org/show_bug.cgi?id=18819
+ else if (ea->op == TOKarrayliteral)
+ result = interpret((ArrayLiteralExp *)ea, istate);
else
assert(0);
if (CTFEExp::isCantExp(result))
diff --git a/gcc/d/dmd/dmangle.c b/gcc/d/dmd/dmangle.c
index 44f4f826b41..f41f6284dc5 100644
--- a/gcc/d/dmd/dmangle.c
+++ b/gcc/d/dmd/dmangle.c
@@ -80,6 +80,7 @@ void initTypeMangle()
mangleChar[Tslice] = "@";
mangleChar[Treturn] = "@";
mangleChar[Tvector] = "@";
+ mangleChar[Ttraits] = "@";
mangleChar[Tnull] = "n"; // same as TypeNone
diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c
index 9aec87a04f5..05ab04c8989 100644
--- a/gcc/d/dmd/dsymbol.c
+++ b/gcc/d/dmd/dsymbol.c
@@ -321,12 +321,12 @@ Dsymbol *Dsymbol::toAlias2()
*/
Dsymbol *Dsymbol::pastMixin()
{
- Dsymbol *s = this;
-
//printf("Dsymbol::pastMixin() %s\n", toChars());
- while (s && s->isTemplateMixin())
- s = s->parent;
- return s;
+ if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
+ return this;
+ if (!parent)
+ return NULL;
+ return parent->pastMixin();
}
/// ditto
@@ -334,7 +334,8 @@ Dsymbol *Dsymbol::pastMixinAndNspace()
{
//printf("Dsymbol::pastMixinAndNspace() %s\n", toChars());
Nspace *ns = isNspace();
- if (!(ns && ns->mangleOnly) && !isTemplateMixin() && !isForwardingAttribDeclaration())
+ if (!(ns && ns->mangleOnly) &&
+ !isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
return this;
if (!parent)
return NULL;
@@ -382,10 +383,12 @@ Dsymbol *Dsymbol::toParent()
/// ditto
Dsymbol *Dsymbol::toParent2()
{
- Dsymbol *s = parent;
- while (s && s->isTemplateInstance())
- s = s->parent;
- return s;
+ if (!parent ||
+ (!parent->isTemplateInstance() &&
+ !parent->isForwardingAttribDeclaration() &&
+ !parent->isForwardingScopeDsymbol()))
+ return parent;
+ return parent->toParent2();
}
/// ditto
@@ -951,6 +954,83 @@ const char *OverloadSet::kind() const
}
+/********************************* ForwardingScopeDsymbol ******************/
+
+ForwardingScopeDsymbol::ForwardingScopeDsymbol(ScopeDsymbol *forward)
+ : ScopeDsymbol()
+{
+ this->forward = forward;
+}
+
+Dsymbol *ForwardingScopeDsymbol::symtabInsert(Dsymbol *s)
+{
+ assert(forward);
+ if (Declaration *d = s->isDeclaration())
+ {
+ if (d->storage_class & STClocal)
+ {
+ // Symbols with storage class STClocal are not
+ // forwarded, but stored in the local symbol
+ // table. (Those are the `static foreach` variables.)
+ if (!symtab)
+ {
+ symtab = new DsymbolTable();
+ }
+ return ScopeDsymbol::symtabInsert(s); // insert locally
+ }
+ }
+ if (!forward->symtab)
+ {
+ forward->symtab = new DsymbolTable();
+ }
+ // Non-STClocal symbols are forwarded to `forward`.
+ return forward->symtabInsert(s);
+}
+
+/************************
+ * This override handles the following two cases:
+ * static foreach (i, i; [0]) { ... }
+ * and
+ * static foreach (i; [0]) { enum i = 2; }
+ */
+Dsymbol *ForwardingScopeDsymbol::symtabLookup(Dsymbol *s, Identifier *id)
+{
+ assert(forward);
+ // correctly diagnose clashing foreach loop variables.
+ if (Declaration *d = s->isDeclaration())
+ {
+ if (d->storage_class & STClocal)
+ {
+ if (!symtab)
+ {
+ symtab = new DsymbolTable();
+ }
+ return ScopeDsymbol::symtabLookup(s,id);
+ }
+ }
+ // Declarations within `static foreach` do not clash with
+ // `static foreach` loop variables.
+ if (!forward->symtab)
+ {
+ forward->symtab = new DsymbolTable();
+ }
+ return forward->symtabLookup(s,id);
+}
+
+void ForwardingScopeDsymbol::importScope(Dsymbol *s, Prot protection)
+{
+ forward->importScope(s, protection);
+}
+
+void ForwardingScopeDsymbol::semantic(Scope *)
+{
+}
+
+const char *ForwardingScopeDsymbol::kind() const
+{
+ return "local scope";
+}
+
/********************************* ScopeDsymbol ****************************/
ScopeDsymbol::ScopeDsymbol()
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index a840261c0bf..788b67e7b74 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -376,8 +376,10 @@ public:
class ForwardingScopeDsymbol : public ScopeDsymbol
{
+public:
ScopeDsymbol *forward;
+ ForwardingScopeDsymbol(ScopeDsymbol *forward);
Dsymbol *symtabInsert(Dsymbol *s);
Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
void importScope(Dsymbol *s, Prot protection);
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
index 5f1bfa8f5a9..ccfb4b69a29 100644
--- a/gcc/d/dmd/expression.c
+++ b/gcc/d/dmd/expression.c
@@ -2185,6 +2185,11 @@ StringExp *Expression::toStringExp()
return NULL;
}
+TupleExp *Expression::toTupleExp()
+{
+ return NULL;
+}
+
/***************************************
* Return !=0 if expression is an lvalue.
*/
@@ -4542,6 +4547,11 @@ Expression *TupleExp::syntaxCopy()
return new TupleExp(loc, e0 ? e0->syntaxCopy() : NULL, arraySyntaxCopy(exps));
}
+TupleExp *TupleExp::toTupleExp()
+{
+ return this;
+}
+
/******************************** FuncExp *********************************/
FuncExp::FuncExp(Loc loc, Dsymbol *s)
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index b460e8caa01..60448600e24 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -157,6 +157,7 @@ public:
virtual real_t toImaginary();
virtual complex_t toComplex();
virtual StringExp *toStringExp();
+ virtual TupleExp *toTupleExp();
virtual bool isLvalue();
virtual Expression *toLvalue(Scope *sc, Expression *e);
virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -397,6 +398,7 @@ public:
TupleExp(Loc loc, Expression *e0, Expressions *exps);
TupleExp(Loc loc, Expressions *exps);
TupleExp(Loc loc, TupleDeclaration *tup);
+ TupleExp *toTupleExp();
Expression *syntaxCopy();
bool equals(RootObject *o);
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
index c23e332b180..781bd3ea5fd 100644
--- a/gcc/d/dmd/expressionsem.c
+++ b/gcc/d/dmd/expressionsem.c
@@ -1758,15 +1758,30 @@ public:
else
{
// Disallow shadowing
- for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing)
+ for (Scope *scx = sc->enclosing; scx && (scx->func == sc->func || (scx->func && sc->func->fes)); scx = scx->enclosing)
{
Dsymbol *s2;
if (scx->scopesym && scx->scopesym->symtab &&
(s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
s != s2)
{
- e->error("%s %s is shadowing %s %s", s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
- return setError();
+ // allow STClocal symbols to be shadowed
+ // TODO: not reallly an optimal design
+ Declaration *decl = s2->isDeclaration();
+ if (!decl || !(decl->storage_class & STClocal))
+ {
+ if (sc->func->fes)
+ {
+ e->deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.",
+ s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
+ }
+ else
+ {
+ e->error("%s %s is shadowing %s %s",
+ s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
+ return setError();
+ }
+ }
}
}
}
@@ -7930,6 +7945,12 @@ public:
if (f1 || f2)
return setError();
+ if (exp->e1->op == TOKtype || exp->e2->op == TOKtype)
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
exp->type = Type::tbool;
if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
index 11e4b2f721b..ab74dc5328b 100644
--- a/gcc/d/dmd/func.c
+++ b/gcc/d/dmd/func.c
@@ -1491,8 +1491,7 @@ void FuncDeclaration::semantic3(Scope *sc)
* e.g.
* class C { int x; static assert(is(typeof({ this.x = 1; }))); }
*
- * To properly accept it, mark these lambdas as member functions -
- * isThis() returns true and isNested() returns false.
+ * To properly accept it, mark these lambdas as member functions.
*/
if (FuncLiteralDeclaration *fld = isFuncLiteralDeclaration())
{
@@ -1510,7 +1509,6 @@ void FuncDeclaration::semantic3(Scope *sc)
if (fld->tok != TOKfunction)
fld->tok = TOKdelegate;
}
- assert(!isNested());
}
}
diff --git a/gcc/d/dmd/hdrgen.c b/gcc/d/dmd/hdrgen.c
index 395aa3212b5..2436f6eba8f 100644
--- a/gcc/d/dmd/hdrgen.c
+++ b/gcc/d/dmd/hdrgen.c
@@ -249,7 +249,7 @@ public:
buf->writenl();
}
- void visit(ForeachStatement *s)
+ void foreachWithoutBody(ForeachStatement *s)
{
buf->writestring(Token::toChars(s->op));
buf->writestring(" (");
@@ -269,6 +269,11 @@ public:
s->aggr->accept(this);
buf->writeByte(')');
buf->writenl();
+ }
+
+ void visit(ForeachStatement *s)
+ {
+ foreachWithoutBody(s);
buf->writeByte('{');
buf->writenl();
buf->level++;
@@ -279,7 +284,7 @@ public:
buf->writenl();
}
- void visit(ForeachRangeStatement *s)
+ void foreachRangeWithoutBody(ForeachRangeStatement *s)
{
buf->writestring(Token::toChars(s->op));
buf->writestring(" (");
@@ -297,6 +302,11 @@ public:
buf->writenl();
buf->writeByte('{');
buf->writenl();
+ }
+
+ void visit(ForeachRangeStatement *s)
+ {
+ foreachRangeWithoutBody(s);
buf->level++;
if (s->_body)
s->_body->accept(this);
@@ -305,6 +315,20 @@ public:
buf->writenl();
}
+ void visit(StaticForeachStatement *s)
+ {
+ buf->writestring("static ");
+ if (s->sfe->aggrfe)
+ {
+ visit(s->sfe->aggrfe);
+ }
+ else
+ {
+ assert(s->sfe->rangefe);
+ visit(s->sfe->rangefe);
+ }
+ }
+
void visit(IfStatement *s)
{
buf->writestring("if (");
@@ -767,6 +791,12 @@ public:
buf->writestring(t->dstring);
}
+ void visit(TypeTraits *t)
+ {
+ //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
+ t->exp->accept(this);
+ }
+
void visit(TypeVector *t)
{
//printf("TypeVector::toCBuffer2(t->mod = %d)\n", t->mod);
@@ -1360,6 +1390,32 @@ public:
buf->writenl();
}
+ void visit(ForwardingStatement *s)
+ {
+ s->statement->accept(this);
+ }
+
+ void visit(StaticForeachDeclaration *s)
+ {
+ buf->writestring("static ");
+ if (s->sfe->aggrfe)
+ {
+ foreachWithoutBody(s->sfe->aggrfe);
+ }
+ else
+ {
+ assert(s->sfe->rangefe);
+ foreachRangeWithoutBody(s->sfe->rangefe);
+ }
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ visit((AttribDeclaration *)s);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
void visit(CompileDeclaration *d)
{
buf->writestring("mixin(");
@@ -1787,6 +1843,8 @@ public:
void visit(AliasDeclaration *d)
{
+ if (d->storage_class & STClocal)
+ return;
buf->writestring("alias ");
if (d->aliassym)
{
@@ -1818,6 +1876,8 @@ public:
void visit(VarDeclaration *d)
{
+ if (d->storage_class & STClocal)
+ return;
visitVarDecl(d, false);
buf->writeByte(';');
buf->writenl();
@@ -2653,7 +2713,8 @@ public:
void visit(TraitsExp *e)
{
buf->writestring("__traits(");
- buf->writestring(e->ident->toChars());
+ if (e->ident)
+ buf->writestring(e->ident->toChars());
if (e->args)
{
for (size_t i = 0; i < e->args->dim; i++)
@@ -3241,6 +3302,7 @@ const char *stcToChars(StorageClass& stc)
{ STCsystem, TOKat, "@system" },
{ STCdisable, TOKat, "@disable" },
{ STCfuture, TOKat, "@__future" },
+ { STClocal, TOKat, "__local" },
{ 0, TOKreserved, NULL }
};
diff --git a/gcc/d/dmd/init.c b/gcc/d/dmd/init.c
index b40ebe3d953..7bd44ab1fc2 100644
--- a/gcc/d/dmd/init.c
+++ b/gcc/d/dmd/init.c
@@ -238,7 +238,7 @@ bool hasNonConstPointers(Expression *e)
return arrayHasNonConstPointers(ae->keys);
return false;
}
- if(e->op == TOKaddress)
+ if (e->op == TOKaddress)
{
AddrExp *ae = (AddrExp *)e;
if (ae->e1->op == TOKstructliteral)
diff --git a/gcc/d/dmd/intrange.c b/gcc/d/dmd/intrange.c
index e0e2472b502..c56d7ba8a93 100644
--- a/gcc/d/dmd/intrange.c
+++ b/gcc/d/dmd/intrange.c
@@ -610,7 +610,7 @@ IntRange IntRange::operator/(const IntRange& rhs) const
{
r.imax.value--;
}
- else if(r.imin.value == 0)
+ else if (r.imin.value == 0)
{
r.imin.value++;
}
diff --git a/gcc/d/dmd/json.c b/gcc/d/dmd/json.c
index acdafa530d2..fa49e9240e2 100644
--- a/gcc/d/dmd/json.c
+++ b/gcc/d/dmd/json.c
@@ -454,6 +454,8 @@ public:
void jsonProperties(Declaration *d)
{
+ if (d->storage_class & STClocal)
+ return;
jsonProperties((Dsymbol *)d);
propertyStorageClass("storageClass", d->storage_class);
@@ -843,6 +845,8 @@ public:
void visit(VarDeclaration *d)
{
+ if (d->storage_class & STClocal)
+ return;
objectStart();
jsonProperties(d);
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
index b76b5baad25..aa1880624ce 100644
--- a/gcc/d/dmd/mtype.c
+++ b/gcc/d/dmd/mtype.c
@@ -202,6 +202,7 @@ void Type::_init()
sizeTy[Terror] = sizeof(TypeError);
sizeTy[Tnull] = sizeof(TypeNull);
sizeTy[Tvector] = sizeof(TypeVector);
+ sizeTy[Ttraits] = sizeof(TypeTraits);
initTypeMangle();
@@ -6459,7 +6460,7 @@ Type *TypeDelegate::addStorageClass(StorageClass stc)
* alias dg_t = void* delegate();
* scope dg_t dg = ...;
*/
- if(stc & STCscope)
+ if (stc & STCscope)
{
Type *n = t->next->addStorageClass(STCscope | STCscopeinferred);
if (n != t->next)
@@ -6554,7 +6555,156 @@ bool TypeDelegate::hasPointers()
return true;
}
+/***************************** TypeTraits ********************************/
+
+TypeTraits::TypeTraits(const Loc &loc, TraitsExp *exp)
+ : Type(Ttraits)
+{
+ this->loc = loc;
+ this->exp = exp;
+ this->sym = NULL;
+}
+
+Type *TypeTraits::syntaxCopy()
+{
+ TraitsExp *te = (TraitsExp *) exp->syntaxCopy();
+ TypeTraits *tt = new TypeTraits(loc, te);
+ tt->mod = mod;
+ 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::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->dim);
+ for (size_t i = 0; i < elems->dim; 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))
+ *pt = t;
+ else if (sym)
+ *ps = sym;
+ else
+ *pt = Type::terror;
+}
+
+d_uns64 TypeTraits::size(Loc)
+{
+ return SIZE_INVALID;
+}
/***************************** TypeQualified *****************************/
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index aab0d034cf0..22fabf585ea 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -94,6 +94,7 @@ enum ENUMTY
Tvector,
Tint128,
Tuns128,
+ Ttraits,
TMAX
};
typedef unsigned char TY; // ENUMTY
@@ -659,6 +660,23 @@ public:
void accept(Visitor *v) { v->visit(this); }
};
+class TypeTraits : public Type
+{
+public:
+ Loc loc;
+ /// The expression to resolve as type or symbol.
+ TraitsExp *exp;
+ /// The symbol when exp doesn't represent a type.
+ Dsymbol *sym;
+
+ 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); }
+};
+
class TypeQualified : public Type
{
public:
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c
index 9da58af046d..b66bddb8ef8 100644
--- a/gcc/d/dmd/parse.c
+++ b/gcc/d/dmd/parse.c
@@ -351,6 +351,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
case TOKunion:
case TOKclass:
case TOKinterface:
+ case TOKtraits:
Ldeclaration:
a = parseDeclarations(false, pAttrs, pAttrs->comment);
if (a && a->dim)
@@ -485,6 +486,10 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
a = parseImport();
// keep pLastDecl
}
+ else if (next == TOKforeach || next == TOKforeach_reverse)
+ {
+ s = parseForeachStaticDecl(token.loc, pLastDecl);
+ }
else
{
stc = STCstatic;
@@ -3144,6 +3149,18 @@ Type *Parser::parseBasicType(bool dontLookDotIdents)
t = parseVector();
break;
+ case TOKtraits:
+ if (TraitsExp *te = (TraitsExp *) parsePrimaryExp())
+ {
+ if (te->ident && te->args)
+ {
+ t = new TypeTraits(token.loc, te);
+ break;
+ }
+ }
+ t = new TypeError();
+ break;
+
case TOKconst:
// const(type)
nextToken();
@@ -4700,6 +4717,161 @@ void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident)
}
/*****************************************
+ * Parses `foreach` statements, `static foreach` statements and
+ * `static foreach` declarations. The template parameter
+ * `isStatic` is true, iff a `static foreach` should be parsed.
+ * If `isStatic` is true, `isDecl` can be true to indicate that a
+ * `static foreach` declaration should be parsed.
+ */
+Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl)
+{
+ TOK op = token.value;
+
+ nextToken();
+ check(TOKlparen);
+
+ Parameters *parameters = new Parameters();
+
+ while (1)
+ {
+ Identifier *ai = NULL;
+ Type *at;
+
+ StorageClass storageClass = 0;
+ StorageClass stc = 0;
+ Lagain:
+ if (stc)
+ {
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+ switch (token.value)
+ {
+ case TOKref:
+ stc = STCref;
+ goto Lagain;
+
+ case TOKenum:
+ stc = STCmanifest;
+ goto Lagain;
+
+ case TOKalias:
+ storageClass = appendStorageClass(storageClass, STCalias);
+ nextToken();
+ break;
+
+ case TOKconst:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCconst;
+ goto Lagain;
+ }
+ break;
+
+ case TOKimmutable:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCimmutable;
+ goto Lagain;
+ }
+ break;
+
+ case TOKshared:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCshared;
+ goto Lagain;
+ }
+ break;
+
+ case TOKwild:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCwild;
+ goto Lagain;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (token.value == TOKidentifier)
+ {
+ Token *t = peek(&token);
+ if (t->value == TOKcomma || t->value == TOKsemicolon)
+ { ai = token.ident;
+ at = NULL; // infer argument type
+ nextToken();
+ goto Larg;
+ }
+ }
+ at = parseType(&ai);
+ if (!ai)
+ error("no identifier for declarator %s", at->toChars());
+ Larg:
+ Parameter *p = new Parameter(storageClass, at, ai, NULL);
+ parameters->push(p);
+ if (token.value == TOKcomma)
+ { nextToken();
+ continue;
+ }
+ break;
+ }
+ check(TOKsemicolon);
+
+ Expression *aggr = parseExpression();
+ if (token.value == TOKslice && parameters->dim == 1)
+ {
+ Parameter *p = (*parameters)[0];
+ delete parameters;
+ nextToken();
+ Expression *upr = parseExpression();
+ check(TOKrparen);
+ Loc endloc;
+ Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
+ if (isRange)
+ *isRange = true;
+ return new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
+ }
+ else
+ {
+ check(TOKrparen);
+ Loc endloc;
+ Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
+ if (isRange)
+ *isRange = false;
+ return new ForeachStatement(loc, op, parameters, aggr, body, endloc);
+ }
+}
+
+Dsymbol *Parser::parseForeachStaticDecl(Loc loc, Dsymbol **pLastDecl)
+{
+ nextToken();
+
+ bool isRange = false;
+ Statement *s = parseForeach(loc, &isRange, true);
+
+ return new StaticForeachDeclaration(
+ new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s,
+ isRange ? (ForeachRangeStatement *)s : NULL),
+ parseBlock(pLastDecl)
+ );
+}
+
+Statement *Parser::parseForeachStatic(Loc loc)
+{
+ nextToken();
+
+ bool isRange = false;
+ Statement *s = parseForeach(loc, &isRange, false);
+
+ return new StaticForeachStatement(loc,
+ new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s,
+ isRange ? (ForeachRangeStatement *)s : NULL)
+ );
+}
+
+/*****************************************
* Input:
* flags PSxxxx
* Output:
@@ -4757,6 +4929,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
case TOKdot:
case TOKtypeof:
case TOKvector:
+ case TOKtraits:
/* Bugzilla 15163: If tokens can be handled as
* old C-style declaration or D expression, prefer the latter.
*/
@@ -4805,7 +4978,6 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
case TOKtypeid:
case TOKis:
case TOKlbracket:
- case TOKtraits:
case TOKfile:
case TOKfilefullpath:
case TOKline:
@@ -4834,6 +5006,13 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
cond = parseStaticIfCondition();
goto Lcondition;
}
+ else if (t->value == TOKforeach || t->value == TOKforeach_reverse)
+ {
+ s = parseForeachStatic(loc);
+ if (flags & PSscope)
+ s = new ScopeStatement(loc, s, token.loc);
+ break;
+ }
if (t->value == TOKimport)
{
Dsymbols *imports = parseImport();
@@ -5086,106 +5265,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
case TOKforeach:
case TOKforeach_reverse:
{
- TOK op = token.value;
-
- nextToken();
- check(TOKlparen);
-
- Parameters *parameters = new Parameters();
-
- while (1)
- {
- Identifier *ai = NULL;
- Type *at;
-
- StorageClass storageClass = 0;
- StorageClass stc = 0;
- Lagain:
- if (stc)
- {
- storageClass = appendStorageClass(storageClass, stc);
- nextToken();
- }
- switch (token.value)
- {
- case TOKref:
- stc = STCref;
- goto Lagain;
-
- case TOKconst:
- if (peekNext() != TOKlparen)
- {
- stc = STCconst;
- goto Lagain;
- }
- break;
- case TOKimmutable:
- if (peekNext() != TOKlparen)
- {
- stc = STCimmutable;
- goto Lagain;
- }
- break;
- case TOKshared:
- if (peekNext() != TOKlparen)
- {
- stc = STCshared;
- goto Lagain;
- }
- break;
- case TOKwild:
- if (peekNext() != TOKlparen)
- {
- stc = STCwild;
- goto Lagain;
- }
- break;
- default:
- break;
- }
- if (token.value == TOKidentifier)
- {
- Token *t = peek(&token);
- if (t->value == TOKcomma || t->value == TOKsemicolon)
- { ai = token.ident;
- at = NULL; // infer argument type
- nextToken();
- goto Larg;
- }
- }
- at = parseType(&ai);
- if (!ai)
- error("no identifier for declarator %s", at->toChars());
- Larg:
- Parameter *p = new Parameter(storageClass, at, ai, NULL);
- parameters->push(p);
- if (token.value == TOKcomma)
- { nextToken();
- continue;
- }
- break;
- }
- check(TOKsemicolon);
-
- Expression *aggr = parseExpression();
- if (token.value == TOKslice && parameters->dim == 1)
- {
- Parameter *p = (*parameters)[0];
- delete parameters;
- nextToken();
- Expression *upr = parseExpression();
- check(TOKrparen);
- Loc endloc;
- Statement *body = parseStatement(0, NULL, &endloc);
- s = new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
- }
- else
- {
- check(TOKrparen);
- Loc endloc;
- Statement *body = parseStatement(0, NULL, &endloc);
- s = new ForeachStatement(loc, op, parameters, aggr, body, endloc);
- }
+ s = parseForeach(loc, NULL, false);
break;
}
@@ -6001,6 +6081,27 @@ bool Parser::isBasicType(Token **pt)
goto Lfalse;
goto L3;
+ case TOKtraits:
+ {
+ // __traits(getMember
+ t = peek(t);
+ if (t->value != TOKlparen)
+ goto Lfalse;
+ Token *lp = t;
+ t = peek(t);
+ if (t->value != TOKidentifier || t->ident != Id::getMember)
+ goto Lfalse;
+ if (!skipParens(lp, &lp))
+ goto Lfalse;
+ // we are in a lookup for decl VS statement
+ // so we expect a declarator following __trait if it's a type.
+ // other usages wont be ambiguous (alias, template instance, type qual, etc.)
+ if (lp->value != TOKidentifier)
+ goto Lfalse;
+
+ break;
+ }
+
case TOKconst:
case TOKimmutable:
case TOKshared:
@@ -7390,6 +7491,7 @@ Expression *Parser::parseUnaryExp()
case TOKfunction:
case TOKdelegate:
case TOKtypeof:
+ case TOKtraits:
case TOKvector:
case TOKfile:
case TOKfilefullpath:
diff --git a/gcc/d/dmd/parse.h b/gcc/d/dmd/parse.h
index 97630dc3c4d..c5ef0b2cdb6 100644
--- a/gcc/d/dmd/parse.h
+++ b/gcc/d/dmd/parse.h
@@ -120,6 +120,9 @@ public:
FuncDeclaration *parseContracts(FuncDeclaration *f);
void checkDanglingElse(Loc elseloc);
void checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident);
+ Statement *parseForeach(Loc loc, bool *isRange, bool isDecl);
+ Dsymbol *parseForeachStaticDecl(Loc loc, Dsymbol **pLastDecl);
+ Statement *parseForeachStatic(Loc loc);
/** endPtr used for documented unittests */
Statement *parseStatement(int flags, const utf8_t** endPtr = NULL, Loc *pEndloc = NULL);
Initializer *parseInitializer();
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index 37a15fc1acc..d34a0e704f7 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -61,9 +61,10 @@ enum PINLINE;
#define SCOPEctfe 0x0080 // inside a ctfe-only expression
#define SCOPEcompile 0x0100 // inside __traits(compile)
#define SCOPEignoresymbolvisibility 0x0200 // ignore symbol visibility (Bugzilla 15907)
-#define SCOPEfullinst 0x1000 // fully instantiate templates
#define SCOPEfree 0x8000 // is on free list
+#define SCOPEfullinst 0x10000 // fully instantiate templates
+#define SCOPEalias 0x20000 // inside alias declaration
struct Scope
{
diff --git a/gcc/d/dmd/statement.c b/gcc/d/dmd/statement.c
index 450b3f4f594..6c3443cb9fa 100644
--- a/gcc/d/dmd/statement.c
+++ b/gcc/d/dmd/statement.c
@@ -32,6 +32,7 @@ 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)
{
@@ -410,6 +411,7 @@ Statement *toStatement(Dsymbol *s)
void visit(ProtDeclaration *d) { result = visitMembers(d->loc, d->decl); }
void visit(AlignDeclaration *d) { result = visitMembers(d->loc, d->decl); }
void visit(UserAttributeDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+ void visit(ForwardingAttribDeclaration *d) { result = visitMembers(d->loc, d->decl); }
void visit(StaticAssert *) {}
void visit(Import *) {}
@@ -420,6 +422,12 @@ Statement *toStatement(Dsymbol *s)
result = visitMembers(d->loc, d->include(NULL, NULL));
}
+ void visit(StaticForeachDeclaration *d)
+ {
+ assert(d->sfe && !!d->sfe->aggrfe ^ !!d->sfe->rangefe);
+ result = visitMembers(d->loc, d->include(NULL, NULL));
+ }
+
void visit(CompileDeclaration *d)
{
result = visitMembers(d->loc, d->include(NULL, NULL));
@@ -682,6 +690,72 @@ bool ScopeStatement::hasContinue()
return statement ? statement->hasContinue() : false;
}
+/******************************** ForwardingStatement **********************/
+
+/* Statement whose symbol table contains foreach index variables in a
+ * local scope and forwards other members to the parent scope. This
+ * wraps a statement.
+ *
+ * Also see: `ddmd.attrib.ForwardingAttribDeclaration`
+ */
+
+ForwardingStatement::ForwardingStatement(Loc loc, ForwardingScopeDsymbol *sym, Statement *s)
+ : Statement(loc)
+{
+ this->sym = sym;
+ assert(s);
+ this->statement = s;
+}
+
+ForwardingStatement::ForwardingStatement(Loc loc, Statement *s)
+ : Statement(loc)
+{
+ this->sym = new ForwardingScopeDsymbol(NULL);
+ this->sym->symtab = new DsymbolTable();
+ assert(s);
+ this->statement = s;
+}
+
+Statement *ForwardingStatement::syntaxCopy()
+{
+ return new ForwardingStatement(loc, statement->syntaxCopy());
+}
+
+/***********************
+ * ForwardingStatements are distributed over the flattened
+ * sequence of statements. This prevents flattening to be
+ * "blocked" by a ForwardingStatement and is necessary, for
+ * example, to support generating scope guards with `static
+ * foreach`:
+ *
+ * static foreach(i; 0 .. 10) scope(exit) writeln(i);
+ * writeln("this is printed first");
+ * // then, it prints 10, 9, 8, 7, ...
+ */
+
+Statements *ForwardingStatement::flatten(Scope *sc)
+{
+ if (!statement)
+ {
+ return NULL;
+ }
+ sc = sc->push(sym);
+ Statements *a = statement->flatten(sc);
+ sc = sc->pop();
+ if (!a)
+ {
+ return a;
+ }
+ Statements *b = new Statements();
+ b->setDim(a->dim);
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ Statement *s = (*a)[i];
+ (*b)[i] = s ? new ForwardingStatement(s->loc, sym, s) : NULL;
+ }
+ return b;
+}
+
/******************************** WhileStatement ***************************/
WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc)
@@ -935,6 +1009,52 @@ Statements *ConditionalStatement::flatten(Scope *sc)
return a;
}
+/******************************** StaticForeachStatement ********************/
+
+/* Static foreach statements, like:
+ * void main()
+ * {
+ * static foreach(i; 0 .. 10)
+ * {
+ * pragma(msg, i);
+ * }
+ * }
+ */
+
+StaticForeachStatement::StaticForeachStatement(Loc loc, StaticForeach *sfe)
+ : Statement(loc)
+{
+ this->sfe = sfe;
+}
+
+Statement *StaticForeachStatement::syntaxCopy()
+{
+ return new StaticForeachStatement(loc, sfe->syntaxCopy());
+}
+
+Statements *StaticForeachStatement::flatten(Scope *sc)
+{
+ staticForeachPrepare(sfe, sc);
+ if (staticForeachReady(sfe))
+ {
+ Statement *s = makeTupleForeachStatic(sc, sfe->aggrfe, sfe->needExpansion);
+ Statements *result = s->flatten(sc);
+ if (result)
+ {
+ return result;
+ }
+ result = new Statements();
+ result->push(s);
+ return result;
+ }
+ else
+ {
+ Statements *result = new Statements();
+ result->push(new ErrorStatement());
+ return result;
+ }
+}
+
/******************************** PragmaStatement ***************************/
PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index fae0862b4d6..8f69383bb3a 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -232,15 +232,13 @@ public:
class ForwardingStatement : public Statement
{
+public:
ForwardingScopeDsymbol *sym;
Statement *statement;
+ ForwardingStatement(Loc loc, ForwardingScopeDsymbol *sym, Statement *s);
+ ForwardingStatement(Loc loc, Statement *s);
Statement *syntaxCopy();
- Statement *getRelatedLabeled();
- bool hasBreak();
- bool hasContinue();
- Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally);
- Statement *last();
Statements *flatten(Scope *sc);
ForwardingStatement *isForwardingStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -384,6 +382,7 @@ class StaticForeachStatement : public Statement
public:
StaticForeach *sfe;
+ StaticForeachStatement(Loc loc, StaticForeach *sfe);
Statement *syntaxCopy();
Statements *flatten(Scope *sc);
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
index cc2b63e2466..26e5950518a 100644
--- a/gcc/d/dmd/statementsem.c
+++ b/gcc/d/dmd/statementsem.c
@@ -13,6 +13,7 @@
#include "errors.h"
#include "statement.h"
+#include "attrib.h"
#include "expression.h"
#include "cond.h"
#include "init.h"
@@ -303,11 +304,10 @@ public:
void visit(ScopeStatement *ss)
{
- ScopeDsymbol *sym;
//printf("ScopeStatement::semantic(sc = %p)\n", sc);
if (ss->statement)
{
- sym = new ScopeDsymbol();
+ ScopeDsymbol *sym = new ScopeDsymbol();
sym->parent = sc->scopesym;
sym->endlinnum = ss->endloc.linnum;
sc = sc->push(sym);
@@ -348,6 +348,22 @@ public:
result = ss;
}
+ void visit(ForwardingStatement *ss)
+ {
+ assert(ss->sym);
+ for (Scope *csc = sc; !ss->sym->forward; csc = csc->enclosing)
+ {
+ assert(csc);
+ ss->sym->forward = csc->scopesym;
+ }
+ sc = sc->push(ss->sym);
+ sc->sbreak = ss;
+ sc->scontinue = ss;
+ ss->statement = semantic(ss->statement, sc);
+ sc = sc->pop();
+ result = ss->statement;
+ }
+
void visit(WhileStatement *ws)
{
/* Rewrite as a for(;condition;) loop
@@ -478,6 +494,347 @@ public:
result = fs;
}
+ /***********************
+ * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
+ *
+ * Params:
+ * storageClass = The storage class of the variable.
+ * type = The declared type of the variable.
+ * ident = The name of the variable.
+ * e = The initializer of the variable (i.e. the current element of the looped over aggregate).
+ * t = The type of the initializer.
+ * Returns:
+ * `true` iff the declaration was successful.
+ */
+ bool declareVariable(ForeachStatement *fs, Type *paramtype, TupleExp *te,
+ bool needExpansion, bool isStatic, Statements *statements, Dsymbols *declarations,
+ StorageClass storageClass, Type *type, Identifier *ident, Expression *e, Type *t)
+ {
+ Loc loc = fs->loc;
+ if (storageClass & (STCout | STClazy) ||
+ (storageClass & STCref && !te))
+ {
+ fs->error("no storage class for value %s", ident->toChars());
+ return false;
+ }
+ Declaration *var;
+ if (e)
+ {
+ Type *tb = e->type->toBasetype();
+ Dsymbol *ds = NULL;
+ if (!(storageClass & STCmanifest))
+ {
+ if ((isStatic || tb->ty == Tfunction || tb->ty == Tsarray || storageClass & STCalias) && e->op == TOKvar)
+ ds = ((VarExp *)e)->var;
+ else if (e->op == TOKtemplate)
+ ds = ((TemplateExp *)e)->td;
+ else if (e->op == TOKscope)
+ ds = ((ScopeExp *)e)->sds;
+ else if (e->op == TOKfunction)
+ {
+ FuncExp *fe = (FuncExp *)e;
+ ds = fe->td ? (Dsymbol *)fe->td : fe->fd;
+ }
+ }
+ else if (storageClass & STCalias)
+ {
+ fs->error("foreach loop variable cannot be both enum and alias");
+ return false;
+ }
+
+ if (ds)
+ {
+ var = new AliasDeclaration(loc, ident, ds);
+ if (storageClass & STCref)
+ {
+ fs->error("symbol %s cannot be ref", ds->toChars());
+ return false;
+ }
+ if (paramtype)
+ {
+ fs->error("cannot specify element type for symbol %s", ds->toChars());
+ return false;
+ }
+ }
+ else if (e->op == TOKtype)
+ {
+ var = new AliasDeclaration(loc, ident, e->type);
+ if (paramtype)
+ {
+ fs->error("cannot specify element type for type %s", e->type->toChars());
+ return false;
+ }
+ }
+ else
+ {
+ e = resolveProperties(sc, e);
+ type = e->type;
+ if (paramtype)
+ type = paramtype;
+ Initializer *ie = new ExpInitializer(Loc(), e);
+ VarDeclaration *v = new VarDeclaration(loc, type, ident, ie);
+ if (storageClass & STCref)
+ v->storage_class |= STCref | STCforeach;
+ if (isStatic || storageClass & STCmanifest || e->isConst() ||
+ e->op == TOKstring ||
+ e->op == TOKstructliteral ||
+ e->op == TOKarrayliteral)
+ {
+ if (v->storage_class & STCref)
+ {
+ if (!isStatic || !needExpansion)
+ {
+ fs->error("constant value %s cannot be ref", ie->toChars());
+ }
+ else
+ {
+ fs->error("constant value %s cannot be ref", ident->toChars());
+ }
+ return false;
+ }
+ else
+ v->storage_class |= STCmanifest;
+ }
+ var = v;
+ }
+ }
+ else
+ {
+ var = new AliasDeclaration(loc, ident, t);
+ if (paramtype)
+ {
+ fs->error("cannot specify element type for symbol %s", fs->toChars());
+ return false;
+ }
+ }
+ if (isStatic)
+ var->storage_class |= STClocal;
+ if (statements)
+ statements->push(new ExpStatement(loc, var));
+ else if (declarations)
+ declarations->push(var);
+ else
+ assert(0);
+ return true;
+ }
+
+ bool makeTupleForeachBody(ForeachStatement *fs, size_t k,
+ Type *paramtype, TupleExp *te, TypeTuple *tuple,
+ bool needExpansion, bool isStatic, bool isDecl,
+ Statements *statements, Dsymbols *declarations, Dsymbols *dbody)
+ {
+ Loc loc = fs->loc;
+ Expression *e = NULL;
+ Type *t = NULL;
+ if (te)
+ e = (*te->exps)[k];
+ else
+ t = Parameter::getNth(tuple->arguments, k)->type;
+ Parameter *p = (*fs->parameters)[0];
+ Statements *stmts = (isDecl) ? NULL : new Statements();
+ Dsymbols *decls = (isDecl) ? new Dsymbols() : NULL;
+
+ size_t dim = fs->parameters->dim;
+ if (!needExpansion && dim == 2)
+ {
+ // Declare key
+ if (p->storageClass & (STCout | STCref | STClazy))
+ {
+ fs->error("no storage class for key %s", p->ident->toChars());
+ return false;
+ }
+ if (isStatic)
+ {
+ if (!p->type)
+ {
+ p->type = Type::tsize_t;
+ }
+ }
+ p->type = p->type->semantic(loc, sc);
+ TY keyty = p->type->ty;
+ if (keyty != Tint32 && keyty != Tuns32)
+ {
+ if (global.params.isLP64)
+ {
+ if (keyty != Tint64 && keyty != Tuns64)
+ {
+ fs->error("foreach: key type must be int or uint, long or ulong, not %s", p->type->toChars());
+ return false;
+ }
+ }
+ else
+ {
+ fs->error("foreach: key type must be int or uint, not %s", p->type->toChars());
+ return false;
+ }
+ }
+ Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k));
+ VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, ie);
+ var->storage_class |= STCmanifest;
+ if (isStatic)
+ var->storage_class |= STClocal;
+ if (!isDecl)
+ stmts->push(new ExpStatement(loc, var));
+ else
+ decls->push(var);
+ p = (*fs->parameters)[1]; // value
+ }
+
+ if (!isStatic || !needExpansion)
+ {
+ // Declare value
+ if (!declareVariable(fs, paramtype, te, needExpansion, isStatic, stmts, decls,
+ p->storageClass, p->type, p->ident, e, t))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // expand tuples into multiple `static foreach` variables.
+ assert(e && !t);
+ Identifier *ident = Identifier::generateId("__value");
+ declareVariable(fs, paramtype, te, needExpansion, isStatic, stmts, decls,
+ 0, e->type, ident, e, NULL);
+ Identifier *field = Identifier::idPool("tuple");
+ Expression *access = new DotIdExp(loc, e, field);
+ access = semantic(access, sc);
+ if (!tuple)
+ return false;
+ //printf("%s\n", tuple->toChars());
+ for (size_t l = 0; l < dim; l++)
+ {
+ Parameter *cp = (*fs->parameters)[l];
+ Expression *init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type::tsize_t));
+ init_ = semantic(init_, sc);
+ assert(init_->type);
+ declareVariable(fs, paramtype, te, needExpansion, isStatic, stmts, decls,
+ p->storageClass, init_->type, cp->ident, init_, NULL);
+ }
+ }
+ Statement *fwdstmt = NULL;
+ Dsymbol *fwddecl = NULL;
+ if (!isDecl)
+ {
+ if (fs->_body)
+ stmts->push(fs->_body->syntaxCopy());
+ fwdstmt = new CompoundStatement(loc, stmts);
+ }
+ else
+ {
+ decls->append(Dsymbol::arraySyntaxCopy(dbody));
+ }
+ if (!isStatic)
+ {
+ fwdstmt = new ScopeStatement(loc, fwdstmt, fs->endloc);
+ }
+ else if (!isDecl)
+ {
+ fwdstmt = new ForwardingStatement(loc, fwdstmt);
+ }
+ else
+ {
+ fwddecl = new ForwardingAttribDeclaration(decls);
+ }
+
+ if (statements)
+ statements->push(fwdstmt);
+ else if (declarations)
+ declarations->push(fwddecl);
+ else
+ assert(0);
+ return true;
+ }
+
+ /*******************
+ * Type check and unroll `foreach` over an expression tuple as well
+ * as `static foreach` statements and `static foreach`
+ * declarations. For `static foreach` statements and `static
+ * foreach` declarations, the visitor interface is used (and the
+ * result is written into the `result` field.) For `static
+ * foreach` declarations, the resulting Dsymbols* are returned
+ * directly.
+ *
+ * The unrolled body is wrapped into a
+ * - UnrolledLoopStatement, for `foreach` over an expression tuple.
+ * - ForwardingStatement, for `static foreach` statements.
+ * - ForwardingAttribDeclaration, for `static foreach` declarations.
+ *
+ * `static foreach` variables are declared as `STClocal`, such
+ * that they are inserted into the local symbol tables of the
+ * forwarding constructs instead of forwarded. For `static
+ * foreach` with multiple foreach loop variables whose aggregate
+ * has been lowered into a sequence of tuples, this function
+ * expands the tuples into multiple `STClocal` `static foreach`
+ * variables.
+ */
+ bool makeTupleForeach(ForeachStatement *fs, bool needExpansion, bool isStatic, bool isDecl,
+ Statements *statements, Dsymbols *declarations, Dsymbols *dbody)
+ {
+ Loc loc = fs->loc;
+ size_t dim = fs->parameters->dim;
+ if (!needExpansion && (dim < 1 || dim > 2))
+ {
+ fs->error("only one (value) or two (key,value) arguments for tuple foreach");
+ return false;
+ }
+
+ Type *paramtype = (*fs->parameters)[dim-1]->type;
+ if (paramtype)
+ {
+ paramtype = paramtype->semantic(loc, sc);
+ if (paramtype->ty == Terror)
+ return false;
+ }
+
+ Type *tab = fs->aggr->type->toBasetype();
+ TypeTuple *tuple = (TypeTuple *)tab;
+ //printf("aggr: op = %d, %s\n", fs->aggr->op, fs->aggr->toChars());
+ size_t n;
+ TupleExp *te = NULL;
+ if (fs->aggr->op == TOKtuple) // expression tuple
+ {
+ te = (TupleExp *)fs->aggr;
+ n = te->exps->dim;
+ }
+ else if (fs->aggr->op == TOKtype) // type tuple
+ {
+ n = Parameter::dim(tuple->arguments);
+ }
+ else
+ assert(0);
+ for (size_t j = 0; j < n; j++)
+ {
+ size_t k = (fs->op == TOKforeach) ? j : n - 1 - j;
+ if (!makeTupleForeachBody(fs, k, paramtype, te, tuple,
+ needExpansion, isStatic, isDecl,
+ statements, declarations, dbody))
+ return false;
+ }
+ return true;
+ }
+
+ Dsymbols *makeTupleForeachStaticDecl(ForeachStatement *fs, Dsymbols *dbody, bool needExpansion)
+ {
+ assert(sc);
+ Dsymbols *declarations = new Dsymbols();
+ if (!makeTupleForeach(fs, needExpansion, true, true, NULL, declarations, dbody))
+ return NULL;
+
+ return declarations;
+ }
+
+ void makeTupleForeachStatic(ForeachStatement *fs, bool needExpansion)
+ {
+ Loc loc = fs->loc;
+ assert(sc);
+ Statements *statements = new Statements();
+ if (!makeTupleForeach(fs, needExpansion, true, false, statements, NULL, NULL))
+ return setError();
+
+ result = new CompoundStatement(loc, statements);
+ }
+
void visit(ForeachStatement *fs)
{
//printf("ForeachStatement::semantic() %p\n", fs);
@@ -575,177 +932,22 @@ public:
if (tab->ty == Ttuple) // don't generate new scope for tuple loops
{
- if (dim < 1 || dim > 2)
- {
- fs->error("only one (value) or two (key,value) arguments for tuple foreach");
+ Statements *statements = new Statements();
+ if (!makeTupleForeach(fs, false, false, false, statements, NULL, NULL))
return setError();
- }
- Type *paramtype = (*fs->parameters)[dim-1]->type;
- if (paramtype)
- {
- paramtype = paramtype->semantic(loc, sc);
- if (paramtype->ty == Terror)
- return setError();
- }
-
- TypeTuple *tuple = (TypeTuple *)tab;
- Statements *statements = new Statements();
- //printf("aggr: op = %d, %s\n", fs->aggr->op, fs->aggr->toChars());
- size_t n;
- TupleExp *te = NULL;
- if (fs->aggr->op == TOKtuple) // expression tuple
- {
- te = (TupleExp *)fs->aggr;
- n = te->exps->dim;
- }
- else if (fs->aggr->op == TOKtype) // type tuple
+ result = new UnrolledLoopStatement(loc, statements);
+ if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+ ls->gotoTarget = result;
+ if (fs->aggr->op == TOKtuple)
{
- n = Parameter::dim(tuple->arguments);
+ TupleExp *te = (TupleExp *)fs->aggr;
+ if (te->e0)
+ result = new CompoundStatement(loc, new ExpStatement(te->e0->loc, te->e0), result);
}
- else
- assert(0);
- for (size_t j = 0; j < n; j++)
- {
- size_t k = (fs->op == TOKforeach) ? j : n - 1 - j;
- Expression *e = NULL;
- Type *t = NULL;
- if (te)
- e = (*te->exps)[k];
- else
- t = Parameter::getNth(tuple->arguments, k)->type;
- Parameter *p = (*fs->parameters)[0];
- Statements *st = new Statements();
-
- if (dim == 2)
- {
- // Declare key
- if (p->storageClass & (STCout | STCref | STClazy))
- {
- fs->error("no storage class for key %s", p->ident->toChars());
- return setError();
- }
- p->type = p->type->semantic(loc, sc);
- TY keyty = p->type->ty;
- if (keyty != Tint32 && keyty != Tuns32)
- {
- if (global.params.isLP64)
- {
- if (keyty != Tint64 && keyty != Tuns64)
- {
- fs->error("foreach: key type must be int or uint, long or ulong, not %s", p->type->toChars());
- return setError();
- }
- }
- else
- {
- fs->error("foreach: key type must be int or uint, not %s", p->type->toChars());
- return setError();
- }
- }
- Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k));
- VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, ie);
- var->storage_class |= STCmanifest;
- st->push(new ExpStatement(loc, var));
- p = (*fs->parameters)[1]; // value
- }
- // Declare value
- if (p->storageClass & (STCout | STClazy) ||
- (p->storageClass & STCref && !te))
- {
- fs->error("no storage class for value %s", p->ident->toChars());
- return setError();
- }
- Dsymbol *var;
- if (te)
- {
- Type *tb = e->type->toBasetype();
- Dsymbol *ds = NULL;
- if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
- ds = ((VarExp *)e)->var;
- else if (e->op == TOKtemplate)
- ds = ((TemplateExp *)e)->td;
- else if (e->op == TOKscope)
- ds = ((ScopeExp *)e)->sds;
- else if (e->op == TOKfunction)
- {
- FuncExp *fe = (FuncExp *)e;
- ds = fe->td ? (Dsymbol *)fe->td : fe->fd;
- }
-
- if (ds)
- {
- var = new AliasDeclaration(loc, p->ident, ds);
- if (p->storageClass & STCref)
- {
- fs->error("symbol %s cannot be ref", s->toChars());
- return setError();
- }
- if (paramtype)
- {
- fs->error("cannot specify element type for symbol %s", ds->toChars());
- return setError();
- }
- }
- else if (e->op == TOKtype)
- {
- var = new AliasDeclaration(loc, p->ident, e->type);
- if (paramtype)
- {
- fs->error("cannot specify element type for type %s", e->type->toChars());
- return setError();
- }
- }
- else
- {
- p->type = e->type;
- if (paramtype)
- p->type = paramtype;
- Initializer *ie = new ExpInitializer(Loc(), e);
- VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ie);
- if (p->storageClass & STCref)
- v->storage_class |= STCref | STCforeach;
- if (e->isConst() || e->op == TOKstring ||
- e->op == TOKstructliteral || e->op == TOKarrayliteral)
- {
- if (v->storage_class & STCref)
- {
- fs->error("constant value %s cannot be ref", ie->toChars());
- return setError();
- }
- else
- v->storage_class |= STCmanifest;
- }
- var = v;
- }
- }
- else
- {
- var = new AliasDeclaration(loc, p->ident, t);
- if (paramtype)
- {
- fs->error("cannot specify element type for symbol %s", s->toChars());
- return setError();
- }
- }
- st->push(new ExpStatement(loc, var));
-
- if (fs->_body)
- st->push(fs->_body->syntaxCopy());
- s = new CompoundStatement(loc, st);
- s = new ScopeStatement(loc, s, fs->endloc);
- statements->push(s);
- }
-
- s = new UnrolledLoopStatement(loc, statements);
- if (LabelStatement *ls = checkLabeledLoop(sc, fs))
- ls->gotoTarget = s;
- if (te && te->e0)
- s = new CompoundStatement(loc, new ExpStatement(te->e0->loc, te->e0), s);
if (vinit)
- s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
- s = semantic(s, sc);
- result = s;
+ result = new CompoundStatement(loc, new ExpStatement(loc, vinit), result);
+ result = semantic(result, sc);
return;
}
@@ -756,6 +958,19 @@ public:
sc2->noctor++;
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *p = (*fs->parameters)[i];
+ if (p->storageClass & STCmanifest)
+ {
+ fs->error("cannot declare enum loop variables for non-unrolled foreach");
+ }
+ if (p->storageClass & STCalias)
+ {
+ fs->error("cannot declare alias loop variables for non-unrolled foreach");
+ }
+ }
+
switch (tab->ty)
{
case Tarray:
@@ -1949,6 +2164,11 @@ public:
if (ps->_body)
{
+ if (ps->ident == Id::msg || ps->ident == Id::startaddress)
+ {
+ ps->error("`pragma(%s)` is missing a terminating `;`", ps->ident->toChars());
+ return setError();
+ }
ps->_body = semantic(ps->_body, sc);
}
result = ps->_body;
@@ -2862,6 +3082,10 @@ public:
bs->error("break is not inside a loop or switch");
return setError();
}
+ else if (sc->sbreak->isForwardingStatement())
+ {
+ bs->error("must use labeled `break` within `static foreach`");
+ }
result = bs;
}
@@ -2944,6 +3168,10 @@ public:
cs->error("continue is not inside a loop");
return setError();
}
+ else if (sc->scontinue->isForwardingStatement())
+ {
+ cs->error("must use labeled `continue` within `static foreach`");
+ }
result = cs;
}
@@ -3663,3 +3891,20 @@ Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *
scd->pop();
return s;
}
+
+/*******************
+ * See StatementSemanticVisitor.makeTupleForeach. This is a simple
+ * wrapper that returns the generated statements/declarations.
+ */
+Statement *makeTupleForeachStatic(Scope *sc, ForeachStatement *fs, bool needExpansion)
+{
+ StatementSemanticVisitor v = StatementSemanticVisitor(sc);
+ v.makeTupleForeachStatic(fs, needExpansion);
+ return v.result;
+}
+
+Dsymbols *makeTupleForeachStaticDecl(Scope *sc, ForeachStatement *fs, Dsymbols *dbody, bool needExpansion)
+{
+ StatementSemanticVisitor v = StatementSemanticVisitor(sc);
+ return v.makeTupleForeachStaticDecl(fs, dbody, needExpansion);
+}
diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c
index 24303835268..04726c36473 100644
--- a/gcc/d/dmd/traits.c
+++ b/gcc/d/dmd/traits.c
@@ -1182,16 +1182,27 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
{
if (!sm)
return 1;
+
+ // skip local symbols, such as static foreach loop variables
+ if (Declaration *decl = sm->isDeclaration())
+ {
+ if (decl->storage_class & STClocal)
+ {
+ return 0;
+ }
+ }
+
//printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
if (sm->ident)
{
- const char *idx = sm->ident->toChars();
- if (idx[0] == '_' && idx[1] == '_' &&
- sm->ident != Id::ctor &&
- sm->ident != Id::dtor &&
- sm->ident != Id::__xdtor &&
- sm->ident != Id::postblit &&
- sm->ident != Id::__xpostblit)
+ // https://issues.dlang.org/show_bug.cgi?id=10096
+ // https://issues.dlang.org/show_bug.cgi?id=10100
+ // Skip over internal members in __traits(allMembers)
+ if ((sm->isCtorDeclaration() && sm->ident != Id::ctor) ||
+ (sm->isDtorDeclaration() && sm->ident != Id::dtor) ||
+ (sm->isPostBlitDeclaration() && sm->ident != Id::postblit) ||
+ sm->isInvariantDeclaration() ||
+ sm->isUnitTestDeclaration())
{
return 0;
}
@@ -1352,6 +1363,13 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
RootObject *o1 = (*e->args)[0];
RootObject *o2 = (*e->args)[1];
+
+ // issue 12001, allow isSame, <BasicType>, <BasicType>
+ Type *t1 = isType(o1);
+ Type *t2 = isType(o2);
+ if (t1 && t2 && t1->equals(t2))
+ return True(e);
+
Dsymbol *s1 = getDsymbol(o1);
Dsymbol *s2 = getDsymbol(o2);
//printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
@@ -1411,7 +1429,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
TupleExp *te= new TupleExp(e->loc, exps);
return semantic(te, sc);
}
- else if(e->ident == Id::getVirtualIndex)
+ else if (e->ident == Id::getVirtualIndex)
{
if (dim != 1)
return dimError(e, 1, dim);
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index 4c9267044e2..df549da2df7 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -81,6 +81,7 @@ class TypeClass;
class TypeTuple;
class TypeSlice;
class TypeNull;
+class TypeTraits;
class Dsymbol;
@@ -107,6 +108,7 @@ class StaticIfDeclaration;
class CompileDeclaration;
class StaticForeachDeclaration;
class UserAttributeDeclaration;
+class ForwardingAttribDeclaration;
class ScopeDsymbol;
class TemplateDeclaration;
@@ -373,6 +375,7 @@ public:
virtual void visit(TypeTuple *t) { visit((Type *)t); }
virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
virtual void visit(TypeNull *t) { visit((Type *)t); }
+ virtual void visit(TypeTraits *t) { visit((Type *)t); }
virtual void visit(Dsymbol *) { assert(0); }
@@ -399,6 +402,7 @@ public:
virtual void visit(StaticForeachDeclaration *s) { visit((AttribDeclaration *)s); }
virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); }
virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(ForwardingAttribDeclaration *s) { visit((AttribDeclaration *)s); }
virtual void visit(ScopeDsymbol *s) { visit((Dsymbol *)s); }
virtual void visit(TemplateDeclaration *s) { visit((ScopeDsymbol *)s); }