Index: clang/lib/AST/Interp/ByteCodeStmtGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.h +++ clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -60,6 +60,7 @@ bool visitWhileStmt(const WhileStmt *S); bool visitDoStmt(const DoStmt *S); bool visitForStmt(const ForStmt *S); + bool visitCXXForRangeStmt(const CXXForRangeStmt *S); bool visitBreakStmt(const BreakStmt *S); bool visitContinueStmt(const ContinueStmt *S); bool visitSwitchStmt(const SwitchStmt *S); Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -172,6 +172,8 @@ return visitDoStmt(cast(S)); case Stmt::ForStmtClass: return visitForStmt(cast(S)); + case Stmt::CXXForRangeStmtClass: + return visitCXXForRangeStmt(cast(S)); case Stmt::BreakStmtClass: return visitBreakStmt(cast(S)); case Stmt::ContinueStmtClass: @@ -369,6 +371,56 @@ return true; } +template +bool ByteCodeStmtGen::visitCXXForRangeStmt(const CXXForRangeStmt *S) { + const Stmt *Init = S->getInit(); + const Expr *Cond = S->getCond(); + const Expr *Inc = S->getInc(); + const Stmt *Body = S->getBody(); + const Stmt *BeginStmt = S->getBeginStmt(); + const Stmt *RangeStmt = S->getRangeStmt(); + const Stmt *EndStmt = S->getEndStmt(); + const VarDecl *LoopVar = S->getLoopVariable(); + + LabelTy EndLabel = this->getLabel(); + LabelTy CondLabel = this->getLabel(); + LabelTy IncLabel = this->getLabel(); + ExprScope ES(this); + LoopScope LS(this, EndLabel, IncLabel); + + // Emit declarations needed in the loop. + if (Init && !this->visitStmt(Init)) + return false; + if (!this->visitStmt(RangeStmt)) + return false; + if (!this->visitStmt(BeginStmt)) + return false; + if (!this->visitStmt(EndStmt)) + return false; + + // Now the condition as well as the loop variable assignment. + this->emitLabel(CondLabel); + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; + + if (!this->visitVarDecl(LoopVar)) + return false; + + // Body. + if (!this->visitStmt(Body)) + return false; + this->emitLabel(IncLabel); + if (!this->discard(Inc)) + return false; + if (!this->jump(CondLabel)) + return false; + + this->emitLabel(EndLabel); + return true; +} + template bool ByteCodeStmtGen::visitBreakStmt(const BreakStmt *S) { if (!BreakLabel) Index: clang/test/AST/Interp/loops.cpp =================================================================== --- clang/test/AST/Interp/loops.cpp +++ clang/test/AST/Interp/loops.cpp @@ -274,3 +274,53 @@ #endif }; + +namespace RangeForLoop { + constexpr int localArray() { + int a[] = {1,2,3,4}; + int s = 0; + for(int i : a) { + s += i; + } + return s; + } + static_assert(localArray() == 10, ""); + + constexpr int localArray2() { + int a[] = {1,2,3,4}; + int s = 0; + for(const int &i : a) { + s += i; + } + return s; + } + static_assert(localArray2() == 10, ""); + + constexpr int nested() { + int s = 0; + for (const int i : (int[]){1,2,3,4}) { + int a[] = {i, i}; + for(int m : a) { + s += m; + } + } + return s; + } + static_assert(nested() == 20, ""); + + constexpr int withBreak() { + int s = 0; + for (const int &i: (bool[]){false, true}) { + if (i) + break; + s++; + } + return s; + } + static_assert(withBreak() == 1, ""); + + constexpr int NoBody() { + for (const int &i: (bool[]){false, true}); // expected-warning {{empty body}} \ + // ref-warning {{empty body}} + } +}