aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
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 578f3fc..b017c03 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 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");
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index d1f265a..ccfcdda 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 9d7df5f..c75399d 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 8e33b16..576de8c 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 9b24fd2..6179bfd 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 0018d95..806e29d 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 a1658bb..61f5cdb 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 44f4f82..f41f628 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 9aec87a..05ab04c 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 a840261..788b67e 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 5f1bfa8..ccfb4b6 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 b460e8c..6044860 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 c23e332..781bd3e 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 11e4b2f..ab74dc5 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 395aa32..2436f6e 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 b40ebe3..7bd44ab 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 e0e2472..c56d7ba 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 acdafa5..fa49e92 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 b76b5ba..aa18806 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 aab0d03..22fabf5 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 9da58af..b66bddb 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 97630dc..c5ef0b2 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 37a15fc..d34a0e7 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 450b3f4..6c3443c 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 fae0862..8f69383 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 cc2b63e..26e5950 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 2430383..04726c3 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 4c92670..df549da2 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); }