From: Timm Bäder Date: Sat, 31 Dec 2022 15:14:33 +0000 (+0100) Subject: [clang][Interp] Implement C++ Range-for loops X-Git-Tag: upstream/17.0.6~16082 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bce8b3c1830434c10b8a30380db522d7c6a8658d;p=platform%2Fupstream%2Fllvm.git [clang][Interp] Implement C++ Range-for loops Differential Revision: https://reviews.llvm.org/D140803 --- diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index ff2727c..80a81c6 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -172,6 +172,8 @@ bool ByteCodeStmtGen::visitStmt(const Stmt *S) { 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: @@ -370,6 +372,56 @@ bool ByteCodeStmtGen::visitForStmt(const ForStmt *S) { } 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) return false; diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h index 7a30f7b..6b3644ad 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -60,6 +60,7 @@ private: 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); diff --git a/clang/test/AST/Interp/loops.cpp b/clang/test/AST/Interp/loops.cpp index d0386e3..2e23512 100644 --- a/clang/test/AST/Interp/loops.cpp +++ b/clang/test/AST/Interp/loops.cpp @@ -3,10 +3,6 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected-cpp20 %s // RUN: %clang_cc1 -std=c++20 -verify=ref %s -// ref-no-diagnostics -// expected-no-diagnostics -// expected-cpp20-no-diagnostics - namespace WhileLoop { constexpr int f() { int i = 0; @@ -274,3 +270,57 @@ namespace ForLoop { #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 void NoBody() { + for (const int &i: (bool[]){false, true}); // expected-warning {{empty body}} \ + // expected-note {{semicolon on a separate line}} \ + // expected-cpp20-warning {{empty body}} \ + // expected-cpp20-note {{semicolon on a separate line}} \ + // ref-warning {{empty body}} \ + // ref-note {{semicolon on a separate line}} + } +}