diff mbox series

[committed] d: foreach over a tuple doesn't work on 16-bit targets (PR100999)

Message ID 20210611183406.3342246-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: foreach over a tuple doesn't work on 16-bit targets (PR100999) | expand

Commit Message

Iain Buclaw June 11, 2021, 6:34 p.m. UTC
Hi,

This patch improves semantic passes in the front-end around the
`foreach' and `static foreach' statements to be more resilient to
compiling in a minimal D runtime environment.  Checking of the index
type has been improved as well so now there won't be needless compiler
errors when using 8 or 16-bit integers as index types when the size fits
the expected loop range.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32,
committed to mainline, and backported to the gcc-10 and gcc-11 release
branches.

Regards,
Iain.

---
gcc/d/ChangeLog:

	PR d/100999
	* dmd/MERGE: Merge upstream dmd 7a3808254.

libphobos/ChangeLog:

	PR d/100999
	* src/MERGE: Merge upstream phobos 55bb17543.
---
 gcc/d/dmd/MERGE                               |  2 +-
 gcc/d/dmd/cond.c                              | 29 +++++---
 gcc/d/dmd/dinterpret.c                        |  9 +++
 gcc/d/dmd/expression.c                        |  2 +-
 gcc/d/dmd/expressionsem.c                     | 12 ++--
 gcc/d/dmd/statementsem.c                      | 36 +++++-----
 .../compilable/extra-files/minimal/object.d   |  1 +
 .../gdc.test/compilable/interpret5.d          | 30 ++++++++
 gcc/testsuite/gdc.test/compilable/minimal3.d  | 36 ++++++++++
 .../gdc.test/compilable/staticforeach.d       | 38 ++++++++++
 gcc/testsuite/gdc.test/compilable/test21742.d | 13 ++++
 gcc/testsuite/gdc.test/compilable/test22006.d | 14 ++++
 .../gdc.test/fail_compilation/b12504.d        | 64 +++++++++++++++++
 .../gdc.test/fail_compilation/diag16976.d     | 69 ++++++++++++++-----
 .../gdc.test/fail_compilation/fail117.d       |  6 +-
 .../gdc.test/fail_compilation/fail22006.d     | 22 ++++++
 .../gdc.test/fail_compilation/fail238_m32.d   |  8 +--
 .../gdc.test/fail_compilation/fail238_m64.d   |  8 +--
 .../gdc.test/fail_compilation/fail7424b.d     |  2 +-
 .../gdc.test/fail_compilation/fail7424c.d     |  2 +-
 .../gdc.test/fail_compilation/fail7424d.d     |  2 +-
 .../gdc.test/fail_compilation/fail7424e.d     |  2 +-
 .../gdc.test/fail_compilation/fail7424f.d     |  2 +-
 .../gdc.test/fail_compilation/fail7424g.d     |  2 +-
 .../gdc.test/fail_compilation/fail7424h.d     |  2 +-
 .../gdc.test/fail_compilation/fail7424i.d     |  2 +-
 .../gdc.test/fail_compilation/fail9766.d      |  4 +-
 .../gdc.test/fail_compilation/ice9406.d       |  3 +-
 .../gdc.test/fail_compilation/test21927.d     | 20 ++++++
 .../gdc.test/fail_compilation/test21939.d     |  9 +++
 libphobos/src/MERGE                           |  2 +-
 libphobos/src/std/typecons.d                  | 15 ++--
 32 files changed, 388 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/minimal/object.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/interpret5.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/minimal3.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test21742.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test22006.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/b12504.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22006.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test21927.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test21939.d
diff mbox series

Patch

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index a617f285eac..d20785d9126 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-4a4e46a6f304a667e0c05d4455706ec2056ffddc
+7a3808254878df8cb70a055bea58afc79187b778
 
 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/cond.c b/gcc/d/dmd/cond.c
index 6f112ad909c..6c7dc9eb1a3 100644
--- a/gcc/d/dmd/cond.c
+++ b/gcc/d/dmd/cond.c
@@ -112,6 +112,7 @@  static void lowerArrayAggregate(StaticForeach *sfe, Scope *sc)
         sfe->aggrfe->aggr = new TupleExp(aggr->loc, es);
         sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc);
         sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
+        sfe->aggrfe->aggr = sfe->aggrfe->aggr->ctfeInterpret();
     }
     else
     {
@@ -198,7 +199,8 @@  static TypeStruct *createTupleType(Loc loc, Expressions *e)
     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
+    if (global.params.useTypeInfo && Type::dtypeinfo)
+        r->vtinfo = TypeInfoStructDeclaration::create(r); // prevent typeinfo from going to object file
     return r;
 }
 
@@ -312,15 +314,25 @@  static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc)
     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)));
+
+    // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
+    // an empty foreach to expose them.
+    unsigned olderrors = global.startGagging();
+    ety = typeSemantic(ety, aloc, sc);
+    if (global.endGagging(olderrors))
+        s2->push(createForeach(sfe, aloc, pparams[1], NULL));
+    else
+    {
+        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;
     Type *indexty;
 
-    if (sfe->rangefe && (indexty = typeSemantic(ety, aloc, sc))->isintegral())
+    if (sfe->rangefe && (indexty = ety)->isintegral())
     {
         sfe->rangefe->lwr->type = indexty;
         sfe->rangefe->upr->type = indexty;
@@ -384,11 +396,6 @@  void staticForeachPrepare(StaticForeach *sfe, Scope *sc)
         sfe->aggrfe->aggr = expressionSemantic(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)
diff --git a/gcc/d/dmd/dinterpret.c b/gcc/d/dmd/dinterpret.c
index 5e71f3b24a1..ab9d88c660c 100644
--- a/gcc/d/dmd/dinterpret.c
+++ b/gcc/d/dmd/dinterpret.c
@@ -643,7 +643,16 @@  Expression *ctfeInterpret(Expression *e)
     case TOKfloat64:
     case TOKcomplex80:
     case TOKnull:
+    case TOKvoid:
     case TOKstring:
+    case TOKthis:
+    case TOKsuper:
+    case TOKtype:
+    case TOKtypeid:
+    case TOKtemplate:   // non-eponymous template/instance
+    case TOKscope:      // ditto
+    case TOKdottd:      // ditto, e.e1 doesn't matter here
+    case TOKdot:        // ditto
         if (e->type->ty == Terror)
             return new ErrorExp();
         /* fall through */
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
index 88f13e9669b..153819aa172 100644
--- a/gcc/d/dmd/expression.c
+++ b/gcc/d/dmd/expression.c
@@ -1044,7 +1044,7 @@  bool Expression::checkPostblit(Scope *sc, Type *t)
     t = t->baseElemOf();
     if (t->ty == Tstruct)
     {
-        if (global.params.useTypeInfo)
+        if (global.params.useTypeInfo && Type::dtypeinfo)
         {
             // Bugzilla 11395: Require TypeInfo generation for array concatenation
             semanticTypeInfo(sc, t);
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
index 4a37d0fcba2..5ae5fe6a717 100644
--- a/gcc/d/dmd/expressionsem.c
+++ b/gcc/d/dmd/expressionsem.c
@@ -1082,11 +1082,6 @@  static Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2
             if (checkUnsafeAccess(sc, e1, true, true))
                 return new ErrorExp();
         }
-        else if (e1->op == TOKdot)
-        {
-            e1->error("expression has no value");
-            return new ErrorExp();
-        }
         else if (e1->op == TOKcall)
         {
             CallExp *ce = (CallExp *)e1;
@@ -4513,11 +4508,18 @@  public:
 
     void visit(DotTemplateExp *e)
     {
+        if (e->type)
+        {
+            result = e;
+            return;
+        }
         if (Expression *ex = unaSemantic(e, sc))
         {
             result = ex;
             return;
         }
+        // 'void' like TemplateExp
+        e->type = Type::tvoid;
         result = e;
     }
 
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
index 491d9c9bce9..24e534e50a8 100644
--- a/gcc/d/dmd/statementsem.c
+++ b/gcc/d/dmd/statementsem.c
@@ -563,9 +563,6 @@  public:
             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)
@@ -646,22 +643,23 @@  public:
                 }
             }
             p->type = typeSemantic(p->type, loc, sc);
-            TY keyty = p->type->ty;
-            if (keyty != Tint32 && keyty != Tuns32)
+
+            if (!p->type->isintegral())
             {
-                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;
-                }
+                fs->error("foreach: key cannot be of non-integral type `%s`",
+                          p->type->toChars());
+                return false;
+            }
+
+            unsigned length = te ? te->exps->length : tuple->arguments->length;
+            IntRange dimrange = IntRange(SignExtendedNumber(length)).cast(Type::tsize_t);
+            // https://issues.dlang.org/show_bug.cgi?id=12504
+            dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
+            if (!IntRange::fromType(p->type).contains(dimrange))
+            {
+                fs->error("index type `%s` cannot cover index range 0..%llu",
+			  p->type->toChars(), (ulonglong)length);
+                return false;
             }
             Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k));
             VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, ie);
@@ -1073,6 +1071,8 @@  public:
                             {
                                 TypeSArray *ta =  (TypeSArray *)tab;
                                 IntRange dimrange = getIntRange(ta->dim);
+                                // https://issues.dlang.org/show_bug.cgi?id=12504
+                                dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
                                 if (!IntRange::fromType(var->type).contains(dimrange))
                                 {
                                     fs->error("index type `%s` cannot cover index range 0..%llu", p->type->toChars(), ta->dim->toInteger());
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/minimal/object.d b/gcc/testsuite/gdc.test/compilable/extra-files/minimal/object.d
new file mode 100644
index 00000000000..c7060b0d96c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/minimal/object.d
@@ -0,0 +1 @@ 
+module object;
diff --git a/gcc/testsuite/gdc.test/compilable/interpret5.d b/gcc/testsuite/gdc.test/compilable/interpret5.d
new file mode 100644
index 00000000000..ce13a5ab182
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/interpret5.d
@@ -0,0 +1,30 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=21927
+/*
+TEST_OUTPUT:
+---
+T1(Args...)
+T1!()
+T2(Args2...)
+T2!()
+this.T2(Args2...)
+this.T2!()
+---
+*/
+template T1(Args...) {}
+
+pragma(msg, T1);    // TOK.template_
+pragma(msg, T1!()); // TOK.scope_
+
+struct S
+{
+    template T2(Args2...) {}
+
+    pragma(msg, S.T2);    // TOK.template_
+    pragma(msg, S.T2!()); // TOK.scope_
+
+    void fun()
+    {
+        pragma(msg, this.T2);    // TOK.dotTemplateDeclaration
+        pragma(msg, this.T2!()); // TOK.dot
+    }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/minimal3.d b/gcc/testsuite/gdc.test/compilable/minimal3.d
new file mode 100644
index 00000000000..e8106b62003
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/minimal3.d
@@ -0,0 +1,36 @@ 
+// DFLAGS:
+// REQUIRED_ARGS: -defaultlib=
+// EXTRA_SOURCES: extra-files/minimal/object.d
+
+/**********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19234
+void issue19234()
+{
+    static struct A {}
+    A[10] a;
+    A[10] b;
+    b[] = a[];
+}
+
+/**********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=22005
+void issue22005()
+{
+    enum int[4] foo = [1,2,3,4];
+    static foreach (i, e; foo)
+    {
+    }
+}
+
+/**********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=22006
+void issue22006()
+{
+    alias size_t = typeof(int.sizeof);
+    alias AliasSeq(T...) = T;
+
+    foreach (size_t i, e; [0, 1, 2, 3]) { }
+    static foreach (size_t i, e; [0, 1, 2, 3]) { }
+    foreach (size_t i, e; AliasSeq!(0, 1, 2, 3)) { }
+    static foreach (size_t i, e; AliasSeq!(0, 1, 2, 3)) { }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/staticforeach.d b/gcc/testsuite/gdc.test/compilable/staticforeach.d
index 48d06b418d3..8a54f32de57 100644
--- a/gcc/testsuite/gdc.test/compilable/staticforeach.d
+++ b/gcc/testsuite/gdc.test/compilable/staticforeach.d
@@ -115,6 +115,8 @@  bug17688
 T
 foo2
 T2
+TestStaticForeach2
+issue22007
 1 2 '3'
 2 3 '4'
 0 1
@@ -840,3 +842,39 @@  struct T2{
         struct S{}
 }
 static assert(is(__traits(parent,T2.S)==T2));
+
+struct TestStaticForeach2
+{
+static:
+    // StringExp
+    char[] test(string str)()
+    {
+        char[] s;
+        static foreach (c; str)
+        {
+            s ~= c;
+        }
+        return s;
+    }
+    static assert(test!"tёstñ" == ['t', '\xd1', '\x91', 's', 't', '\xc3', '\xb1']);
+
+    static foreach (c; "")
+    {
+        static assert(0);
+    }
+
+    // NullExp
+    enum int[] a = null;
+    static foreach (c; a)
+    {
+        static assert(0);
+    }
+}
+
+//https://issues.dlang.org/show_bug.cgi?id=22007
+void issue22007()
+{
+    immutable int[32] array = 1;
+    foreach (size_t a, int b; array) {}
+    static foreach (size_t a, int b; array) { }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21742.d b/gcc/testsuite/gdc.test/compilable/test21742.d
new file mode 100644
index 00000000000..b8f5df4b46d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21742.d
@@ -0,0 +1,13 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=21742
+
+int foo()() { return 0; }
+
+struct B
+{
+    int foo()() { return 0; }
+}
+
+static assert(is(typeof(foo) == void));
+
+// failed, gagged error: expression B().foo()() has no type
+static assert(is(typeof(B().foo) == void));
diff --git a/gcc/testsuite/gdc.test/compilable/test22006.d b/gcc/testsuite/gdc.test/compilable/test22006.d
new file mode 100644
index 00000000000..913dd859012
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22006.d
@@ -0,0 +1,14 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=22006
+void test22006()
+{
+    alias AliasSeq(TList...) = TList;
+    {
+        alias aseq = AliasSeq!(0, 1, 2, 3);
+        static foreach (ubyte i; 0 .. aseq.length) {}
+        static foreach (ubyte i, x; aseq) {}
+    }
+    {
+        static foreach (ubyte i; 0 .. [0, 1, 2, 3].length) {}
+        static foreach (ubyte i, x; [0, 1, 2, 3]) {}
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b12504.d b/gcc/testsuite/gdc.test/fail_compilation/b12504.d
new file mode 100644
index 00000000000..0bb104eded7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b12504.d
@@ -0,0 +1,64 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b12504.d(26): Error: cannot implicitly convert expression `257$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `ubyte`
+fail_compilation/b12504.d(27): Error: index type `ubyte` cannot cover index range 0..257
+fail_compilation/b12504.d(31): Error: cannot implicitly convert expression `129$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `byte`
+fail_compilation/b12504.d(32): Error: index type `byte` cannot cover index range 0..129
+fail_compilation/b12504.d(36): Error: cannot implicitly convert expression `65537$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `ushort`
+fail_compilation/b12504.d(37): Error: index type `ushort` cannot cover index range 0..65537
+fail_compilation/b12504.d(41): Error: cannot implicitly convert expression `32769$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `short`
+fail_compilation/b12504.d(42): Error: index type `short` cannot cover index range 0..32769
+fail_compilation/b12504.d(46): Error: cannot implicitly convert expression `257$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `ubyte`
+fail_compilation/b12504.d(47): Error: index type `ubyte` cannot cover index range 0..257
+fail_compilation/b12504.d(51): Error: cannot implicitly convert expression `129$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `byte`
+fail_compilation/b12504.d(52): Error: index type `byte` cannot cover index range 0..129
+fail_compilation/b12504.d(56): Error: cannot implicitly convert expression `65537$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `ushort`
+fail_compilation/b12504.d(57): Error: index type `ushort` cannot cover index range 0..65537
+fail_compilation/b12504.d(61): Error: cannot implicitly convert expression `32769$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `short`
+fail_compilation/b12504.d(62): Error: index type `short` cannot cover index range 0..32769
+---
+*/
+void main()
+{
+    {
+        int[0xFF + 2] sta;
+        foreach (ubyte i; 0 .. sta.length) {}
+        foreach (ubyte i, x; sta) {}
+    }
+    {
+        int[0x7F + 2] sta;
+        foreach (byte i; 0 .. sta.length) {}
+        foreach (byte i, x; sta) {}
+    }
+    {
+        int[0xFFFF + 2] sta;
+        foreach (ushort i; 0 .. sta.length) {}
+        foreach (ushort i, x; sta) {}
+    }
+    {
+        int[0x7FFF + 2] sta;
+        foreach (short i; 0 .. sta.length) {}
+        foreach (short i, x; sta) {}
+    }
+    {
+        immutable int[0xFF + 2] sta;
+        static foreach (ubyte i; 0 .. sta.length) {}
+        static foreach (ubyte i, x; sta) {}
+    }
+    {
+        immutable int[0x7F + 2] sta;
+        static foreach (byte i; 0 .. sta.length) {}
+        static foreach (byte i, x; sta) {}
+    }
+    {
+        immutable int[0xFFFF + 2] sta;
+        static foreach (ushort i; 0 .. sta.length) {}
+        static foreach (ushort i, x; sta) {}
+    }
+    {
+        immutable int[0x7FFF + 2] sta;
+        static foreach (short i; 0 .. sta.length) {}
+        static foreach (short i, x; sta) {}
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16976.d b/gcc/testsuite/gdc.test/fail_compilation/diag16976.d
index ebfb72b493c..1dbacfd3e54 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag16976.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag16976.d
@@ -1,21 +1,37 @@ 
 /* TEST_OUTPUT:
 ---
-fail_compilation/diag16976.d(28): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(29): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(30): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(31): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(32): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(33): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(34): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(35): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(36): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(37): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(38): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(39): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(40): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(41): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(42): Error: foreach: key cannot be of non-integral type `float`
-fail_compilation/diag16976.d(43): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(44): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(45): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(46): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(47): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(48): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(49): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(50): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(51): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(52): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(53): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(54): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(55): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(56): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(57): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(58): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(59): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(65): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(66): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(67): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(68): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(69): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(70): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(71): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(72): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(73): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(74): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(75): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(76): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(77): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(78): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(79): Error: foreach: key cannot be of non-integral type `float`
+fail_compilation/diag16976.d(80): Error: foreach: key cannot be of non-integral type `float`
 ---
 */
 
@@ -41,4 +57,25 @@  void main()
     foreach_reverse(float f, dchar i; sta) {}
     foreach_reverse(float f, dchar i; str) {}
     foreach_reverse(float f, dchar i; chr) {}
+
+    immutable int[]  idyn = [1,2,3,4,5];
+    immutable int[5] ista = [1,2,3,4,5];
+    immutable char[]  istr = ['1','2','3','4','5'];
+    immutable char[5] ichr = ['1','2','3','4','5'];
+    static foreach(float f, i; idyn) {}
+    static foreach(float f, i; ista) {}
+    static foreach(float f, i; istr) {}
+    static foreach(float f, i; ichr) {}
+    static foreach(float f, dchar i; idyn) {}
+    static foreach(float f, dchar i; ista) {}
+    static foreach(float f, dchar i; istr) {}
+    static foreach(float f, dchar i; ichr) {}
+    static foreach_reverse(float f, i; idyn) {}
+    static foreach_reverse(float f, i; ista) {}
+    static foreach_reverse(float f, i; istr) {}
+    static foreach_reverse(float f, i; ichr) {}
+    static foreach_reverse(float f, dchar i; idyn) {}
+    static foreach_reverse(float f, dchar i; ista) {}
+    static foreach_reverse(float f, dchar i; istr) {}
+    static foreach_reverse(float f, dchar i; ichr) {}
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail117.d b/gcc/testsuite/gdc.test/fail_compilation/fail117.d
index f39a48db67c..9279d54276c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail117.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail117.d
@@ -1,8 +1,10 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail117.d(35): Error: expression has no value
-fail_compilation/fail117.d(36): Error: expression has no value
+fail_compilation/fail117.d(37): Error: expression `foo.mixin MGettor!(a) geta;
+` is `void` and has no value
+fail_compilation/fail117.d(38): Error: expression `foo.mixin MGettor!(b) getb;
+` is `void` and has no value
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22006.d b/gcc/testsuite/gdc.test/fail_compilation/fail22006.d
new file mode 100644
index 00000000000..89bbc289414
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22006.d
@@ -0,0 +1,22 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22006.d(15): Error: cannot implicitly convert expression `4$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `bool`
+fail_compilation/fail22006.d(16): Error: index type `bool` cannot cover index range 0..4
+fail_compilation/fail22006.d(19): Error: cannot implicitly convert expression `4$?:32=u|64=LU$` of type `$?:32=uint|64=ulong$` to `bool`
+fail_compilation/fail22006.d(20): Error: index type `bool` cannot cover index range 0..4
+---
+*/
+void test22006()
+{
+    alias AliasSeq(TList...) = TList;
+    {
+        alias aseq = AliasSeq!(0, 1, 2, 3);
+        static foreach (bool i; 0 .. aseq.length) {}
+        static foreach (bool i, x; aseq) {}
+    }
+    {
+        static foreach (bool i; 0 .. [0, 1, 2, 3].length) {}
+        static foreach (bool i, x; [0, 1, 2, 3]) {}
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d
index cb565ba2d39..a312dc07290 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d
@@ -3,10 +3,10 @@ 
 TEST_OUTPUT:
 ---
 fail_compilation/fail238_m32.d(21): Error: cannot implicitly convert expression `"a"` of type `string` to `uint`
-fail_compilation/fail238_m32.d(24): Error: cannot interpret X!() at compile time
-fail_compilation/fail238_m32.d(29): Error: template instance fail238_m32.A!"a" error instantiating
-fail_compilation/fail238_m32.d(35):        instantiated from here: M!(q)
-fail_compilation/fail238_m32.d(35):        while evaluating pragma(msg, M!(q))
+fail_compilation/fail238_m32.d(24): Error: cannot implicitly convert expression `X!()` of type `void` to `const(string)`
+fail_compilation/fail238_m32.d(29): Error: template instance `fail238_m32.A!"a"` error instantiating
+fail_compilation/fail238_m32.d(35):        instantiated from here: `M!(q)`
+fail_compilation/fail238_m32.d(35):        while evaluating `pragma(msg, M!(q))`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d
index 08837b2a554..dc7a50ea546 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d
@@ -3,10 +3,10 @@ 
 TEST_OUTPUT:
 ---
 fail_compilation/fail238_m64.d(21): Error: cannot implicitly convert expression `"a"` of type `string` to `ulong`
-fail_compilation/fail238_m64.d(24): Error: cannot interpret X!() at compile time
-fail_compilation/fail238_m64.d(29): Error: template instance fail238_m64.A!"a" error instantiating
-fail_compilation/fail238_m64.d(35):        instantiated from here: M!(q)
-fail_compilation/fail238_m64.d(35):        while evaluating pragma(msg, M!(q))
+fail_compilation/fail238_m64.d(24): Error: cannot implicitly convert expression `X!()` of type `void` to `const(string)`
+fail_compilation/fail238_m64.d(29): Error: template instance `fail238_m64.A!"a"` error instantiating
+fail_compilation/fail238_m64.d(35):        instantiated from here: `M!(q)`
+fail_compilation/fail238_m64.d(35):        while evaluating `pragma(msg, M!(q))`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424b.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424b.d
index 1a7e092fb5b..737958ca6a3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424b.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424b.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424b.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424b
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424c.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424c.d
index 1c0654091f7..e804d72100b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424c.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424c.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424c.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424c
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d
index d784a7580c4..5ef9463aeb2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424d.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424d.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d
index 3bf3a2d97db..ddf4ded953a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424e.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424e.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424e
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d
index 266163de75d..751b6259d31 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424f.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424f.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424f
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424g.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424g.d
index aca6586c8f8..d4fa4635d8d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424g.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424g.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424g.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424g.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424g
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424h.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424h.d
index e08eac13de2..56184a5f5a1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424h.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424h.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424h.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424h.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424g
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d
index 1c2cb1cd687..37042f741f3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424i.d(10): Error: cannot resolve type for this.g()()
+fail_compilation/fail7424i.d(10): Error: expression `this.g()()` is `void` and has no value
 ---
 */
 struct S7424g
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9766.d b/gcc/testsuite/gdc.test/fail_compilation/fail9766.d
index d75d1bc44e7..58cabe3825b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9766.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9766.d
@@ -1,7 +1,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail9766.d(14): Error: cannot interpret Foo!int at compile time
+fail_compilation/fail9766.d(14): Error: integer constant expression expected instead of `Foo!int`
+fail_compilation/fail9766.d(14): Error: alignment must be an integer positive power of 2, not Foo!int
 fail_compilation/fail9766.d(17): Error: alignment must be an integer positive power of 2, not -1
 fail_compilation/fail9766.d(20): Error: alignment must be an integer positive power of 2, not 0
 fail_compilation/fail9766.d(23): Error: alignment must be an integer positive power of 2, not 3
@@ -9,6 +10,7 @@  fail_compilation/fail9766.d(26): Error: alignment must be an integer positive po
 ---
 */
 
+#line 12
 template Foo(T) {}
 
 align(Foo!int)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9406.d b/gcc/testsuite/gdc.test/fail_compilation/ice9406.d
index d8c0837699a..c1807a0f542 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9406.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9406.d
@@ -1,7 +1,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ice9406.d(21): Error: expression has no value
+fail_compilation/ice9406.d(22): Error: `s1.mixin Mixin!() t1;
+` has no effect
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21927.d b/gcc/testsuite/gdc.test/fail_compilation/test21927.d
new file mode 100644
index 00000000000..fa23285e8b0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21927.d
@@ -0,0 +1,20 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=21927
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21927.d(17): Error: invalid `foreach` aggregate `this.T2(Args2...)`
+fail_compilation/test21927.d(18): Error: invalid `foreach` aggregate `this.T2!()`
+---
+*/
+
+struct S
+{
+    template T2(Args2...) {}
+
+    void fun()
+    {
+        // original test case
+        static foreach (p; this.T2) {} // ICE
+        static foreach (p; this.T2!()) {} // ICE
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21939.d b/gcc/testsuite/gdc.test/fail_compilation/test21939.d
new file mode 100644
index 00000000000..cb755ef2679
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21939.d
@@ -0,0 +1,9 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=21939
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21939.d(9): Error: invalid `foreach` aggregate `Object`, define `opApply()`, range primitives, or use `.tupleof`
+---
+*/
+
+static foreach (a; Object) {}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index ac709f9c807..01cf5943b03 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-63f4caa900e17c541042617b2fa187059b86bf88
+55bb17543138a87c376a84745f2a30ec00bdecd9
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index 55119fc2780..84e876f3c59 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -5935,13 +5935,7 @@  mixin template Proxy(alias a)
             // built-in type field, manifest constant, and static non-mutable field
             enum opDispatch = mixin("a."~name);
         }
-        else static if (is(typeof(mixin("a."~name))) || __traits(getOverloads, a, name).length != 0)
-        {
-            // field or property function
-            @property auto ref opDispatch(this X)()                { return mixin("a."~name);        }
-            @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
-        }
-        else
+        else static if (__traits(isTemplate, mixin("a."~name)))
         {
             // member template
             template opDispatch(T...)
@@ -5950,6 +5944,13 @@  mixin template Proxy(alias a)
                 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); }
             }
         }
+        else
+        {
+            // field or property function
+            @property auto ref opDispatch(this X)()                { return mixin("a."~name);        }
+            @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
+        }
+
     }
 
     import std.traits : isArray;