diff --git src/opover.c src/opover.c
index 499bc2e..1f5f5fc 100644
--- src/opover.c
+++ src/opover.c
@@ -1247,8 +1247,40 @@ void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr)
             if (s)
                 goto Lapply;                    // prefer opApply
 
-            if (arguments->dim == 1)
+            if (arguments->dim == 1 || arguments->dim == 2)
             {
+                // foreach index key: foreach(index, value; range) {...}
+                arg = (Parameter *)arguments->data[0];
+                if (arguments->dim == 2 && !arg->type)
+                {
+                    Dsymbol *s = ad->search(0, Id::length, 0);
+                    s = s ? s->toAlias() : NULL;
+
+                    // .length can be a function or a variable
+                    FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
+                    VarDeclaration *vd = s ? s->isVarDeclaration() : NULL;
+
+                    if (!s && op == TOKforeach)
+                    {
+                        // forward iteration does not need r.length; default to size_t
+                        arg->type = Type::tsize_t;
+                    }
+                    else
+                    {
+                        if (fd)
+                            arg->type = fd->type->nextOf();
+                        else if (vd)
+                            arg->type = vd->type;
+                        /*else
+                            break;
+                            // couldn't infer index type, but try inferring value type anyway
+                            // for better diagnostic message
+                        */
+                    }
+                }
+
+                // foreach value: foreach([index,] value; range) {...}
+                arg = (Parameter *)arguments->data[arguments->dim - 1];
                 if (!arg->type)
                 {
                     /* Look for a head() or rear() overload
diff --git src/statement.c src/statement.c
index 5dc9fe3..dbbfc9d 100644
--- src/statement.c
+++ src/statement.c
@@ -1346,6 +1346,9 @@ Statement *ForeachStatement::semantic(Scope *sc)
     Type *tn = NULL;
     Type *tnv = NULL;
 
+    const char *preferredIndexTypes =
+        global.params.isX86_64 ? "int, uint, long or ulong" : "int or uint";
+
     func = sc->func;
     if (func->fes)
         func = func->fes->func;
@@ -1660,13 +1663,16 @@ Lagain:
 #if DMDV2
             /* Prefer using opApply, if it exists
              */
-            if (dim != 1)       // only one argument allowed with ranges
+            if (dim != 1 && dim != 2)   // allows optional index argument
                 goto Lapply;
 
             sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply);
             if (sapply)
                 goto Lapply;
 
+            if (!checkForArgTypes())
+                return this;
+
         {   /* Look for range iteration, i.e. the properties
              * .empty, .next, .retreat, .head and .rear
              *    foreach (e; aggr) { ... }
@@ -1706,22 +1712,66 @@ Lagain:
             Statement *init = new DeclarationStatement(loc, r);
 //printf("init: %s\n", init->toChars());
 
+            /*
+             * Generate an index variable.  The variable is initialized with 0 for foreach
+             * or __r.length for foreach_reverse.
+             */
+            VarDeclaration *index = NULL;
+            if (dim == 2)
+            {
+                Parameter *indexArg = (Parameter *)arguments->data[0];
+                Type *indexType = indexArg->type;
+                Expression *indexInit;
+
+                assert(indexType);
+                indexType = indexType->semantic(loc, sc);
+                if (!indexType->isintegral() || indexType->size() < Type::tsize_t->size())
+                    error("foreach: index type must be %s, not %s",
+                            preferredIndexTypes, indexType->toChars());
+                if (indexArg->storageClass & STCref)
+                    error("foreach: index %s cannot be ref", indexArg->ident->toChars());
+
+                // Declare index variable.
+                if (op == TOKforeach)
+                    indexInit = new IntegerExp(0);
+                else
+                    indexInit = new DotIdExp(loc, new VarExp(loc, r), Id::length);
+                index = new VarDeclaration(loc, indexType, indexArg->ident, new ExpInitializer(loc, indexInit));
+                index->storage_class |= STCforeach;
+                index->storage_class |= indexArg->storageClass & (STCref | STC_TYPECTOR);
+                init = new CompoundStatement(loc, init, new DeclarationStatement(loc, index));
+            }
+
             // !__r.empty
             Expression *e = new VarExp(loc, r);
             e = new DotIdExp(loc, e, Id::Fempty);
             Expression *condition = new NotExp(loc, e);
 
+            if (dim == 2 && op == TOKforeach_reverse)
+            {
+                // insert index-- before the condition: (index--, !__r.empty)
+                e = new PostExp(TOKminusminus, loc, new VarExp(loc, index));
+                condition = new CommaExp(loc, e, condition);
+            }
+
             // __r.next
             e = new VarExp(loc, r);
             Expression *increment = new DotIdExp(loc, e, idnext);
 
+            if (dim == 2 && op == TOKforeach)
+            {
+                // insert index++ after the increment: (__r.next, index++)
+                e = new PostExp(TOKplusplus, loc, new VarExp(loc, index));
+                increment = new CommaExp(loc, increment, e);
+            }
+
             /* Declaration statement for e:
              *    auto e = __r.idhead;
              */
             e = new VarExp(loc, r);
             Expression *einit = new DotIdExp(loc, e, idhead);
 //          einit = einit->semantic(sc);
-            Parameter *arg = (Parameter *)arguments->data[0];
+            Parameter *arg = (Parameter *)arguments->data[dim - 1];
             VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit));
             ve->storage_class |= STCforeach;
             ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
