[clang] 5a85943 - [clang][Interp] Implement while and do-while loops

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 14 05:42:24 PDT 2022


Author: Timm Bäder
Date: 2022-10-14T14:41:05+02:00
New Revision: 5a859432f31716f780cd662741864ef1a77fc28a

URL: https://github.com/llvm/llvm-project/commit/5a859432f31716f780cd662741864ef1a77fc28a
DIFF: https://github.com/llvm/llvm-project/commit/5a859432f31716f780cd662741864ef1a77fc28a.diff

LOG: [clang][Interp] Implement while and do-while loops

Differential Revision: https://reviews.llvm.org/D135433

Added: 
    clang/test/AST/Interp/loops.cpp

Modified: 
    clang/lib/AST/Interp/ByteCodeStmtGen.cpp
    clang/lib/AST/Interp/ByteCodeStmtGen.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 3aa659822bb8..3cdb87fcd7f6 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -153,6 +153,14 @@ bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
     return visitReturnStmt(cast<ReturnStmt>(S));
   case Stmt::IfStmtClass:
     return visitIfStmt(cast<IfStmt>(S));
+  case Stmt::WhileStmtClass:
+    return visitWhileStmt(cast<WhileStmt>(S));
+  case Stmt::DoStmtClass:
+    return visitDoStmt(cast<DoStmt>(S));
+  case Stmt::BreakStmtClass:
+    return visitBreakStmt(cast<BreakStmt>(S));
+  case Stmt::ContinueStmtClass:
+    return visitContinueStmt(cast<ContinueStmt>(S));
   case Stmt::NullStmtClass:
     return true;
   default: {
@@ -262,6 +270,69 @@ bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
   return true;
 }
 
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
+  const Expr *Cond = S->getCond();
+  const Stmt *Body = S->getBody();
+
+  LabelTy CondLabel = this->getLabel(); // Label before the condition.
+  LabelTy EndLabel = this->getLabel();  // Label after the loop.
+  LoopScope<Emitter> LS(this, EndLabel, CondLabel);
+
+  this->emitLabel(CondLabel);
+  if (!this->visitBool(Cond))
+    return false;
+  if (!this->jumpFalse(EndLabel))
+    return false;
+
+  if (!this->visitStmt(Body))
+    return false;
+  if (!this->jump(CondLabel))
+    return false;
+
+  this->emitLabel(EndLabel);
+
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitDoStmt(const DoStmt *S) {
+  const Expr *Cond = S->getCond();
+  const Stmt *Body = S->getBody();
+
+  LabelTy StartLabel = this->getLabel();
+  LabelTy EndLabel = this->getLabel();
+  LabelTy CondLabel = this->getLabel();
+  LoopScope<Emitter> LS(this, EndLabel, CondLabel);
+
+  this->emitLabel(StartLabel);
+  if (!this->visitStmt(Body))
+    return false;
+  this->emitLabel(CondLabel);
+  if (!this->visitBool(Cond))
+    return false;
+  if (!this->jumpTrue(StartLabel))
+    return false;
+  this->emitLabel(EndLabel);
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
+  if (!BreakLabel)
+    return false;
+
+  return this->jump(*BreakLabel);
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
+  if (!ContinueLabel)
+    return false;
+
+  return this->jump(*ContinueLabel);
+}
+
 template <class Emitter>
 bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
   if (!VD->hasLocalStorage()) {

diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h
index 3a9a74038ee3..49a7b79b1c4b 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.h
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h
@@ -58,6 +58,10 @@ class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> {
   bool visitDeclStmt(const DeclStmt *DS);
   bool visitReturnStmt(const ReturnStmt *RS);
   bool visitIfStmt(const IfStmt *IS);
+  bool visitWhileStmt(const WhileStmt *S);
+  bool visitDoStmt(const DoStmt *S);
+  bool visitBreakStmt(const BreakStmt *S);
+  bool visitContinueStmt(const ContinueStmt *S);
 
   /// Compiles a variable declaration.
   bool visitVarDecl(const VarDecl *VD);

diff  --git a/clang/test/AST/Interp/loops.cpp b/clang/test/AST/Interp/loops.cpp
new file mode 100644
index 000000000000..30a38ca573b2
--- /dev/null
+++ b/clang/test/AST/Interp/loops.cpp
@@ -0,0 +1,189 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify=ref %s
+// 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
+
+namespace WhileLoop {
+  constexpr int f() {
+    int i = 0;
+    while(false) {
+      i = i + 1;
+    }
+    return i;
+  }
+  static_assert(f() == 0, "");
+
+
+  constexpr int f2() {
+    int i = 0;
+    while(i != 5) {
+      i = i + 1;
+    }
+    return i;
+  }
+  static_assert(f2() == 5, "");
+
+  constexpr int f3() {
+    int i = 0;
+    while(true) {
+      i = i + 1;
+
+      if (i == 5)
+        break;
+    }
+    return i;
+  }
+  static_assert(f3() == 5, "");
+
+  constexpr int f4() {
+    int i = 0;
+    while(i != 5) {
+
+      i = i + 1;
+      continue;
+      i = i - 1;
+    }
+    return i;
+  }
+  static_assert(f4() == 5, "");
+
+
+  constexpr int f5(bool b) {
+    int i = 0;
+
+    while(true) {
+      if (!b) {
+        if (i == 5)
+          break;
+      }
+
+      if (b) {
+        while (i != 10) {
+          i = i + 1;
+          if (i == 8)
+            break;
+
+          continue;
+        }
+      }
+
+      if (b)
+        break;
+
+      i = i + 1;
+      continue;
+    }
+
+    return i;
+  }
+  static_assert(f5(true) == 8, "");
+  static_assert(f5(false) == 5, "");
+
+#if 0
+  /// FIXME: This is an infinite loop, which should
+  ///   be rejected.
+  constexpr int f6() {
+    while(true);
+  }
+#endif
+};
+
+namespace DoWhileLoop {
+
+  constexpr int f() {
+    int i = 0;
+    do {
+      i = i + 1;
+    } while(false);
+    return i;
+  }
+  static_assert(f() == 1, "");
+
+  constexpr int f2() {
+    int i = 0;
+    do {
+      i = i + 1;
+    } while(i != 5);
+    return i;
+  }
+  static_assert(f2() == 5, "");
+
+
+  constexpr int f3() {
+    int i = 0;
+    do {
+      i = i + 1;
+      if (i == 5)
+        break;
+    } while(true);
+    return i;
+  }
+  static_assert(f3() == 5, "");
+
+  constexpr int f4() {
+    int i = 0;
+    do {
+      i = i + 1;
+      continue;
+      i = i - 1;
+    } while(i != 5);
+    return i;
+  }
+  static_assert(f4() == 5, "");
+
+  constexpr int f5(bool b) {
+    int i = 0;
+
+    do {
+      if (!b) {
+        if (i == 5)
+          break;
+      }
+
+      if (b) {
+        do {
+          i = i + 1;
+          if (i == 8)
+            break;
+
+          continue;
+        } while (i != 10);
+      }
+
+      if (b)
+        break;
+
+      i = i + 1;
+      continue;
+    } while(true);
+
+    return i;
+  }
+  static_assert(f5(true) == 8, "");
+  static_assert(f5(false) == 5, "");
+
+  /// FIXME: This should be accepted in C++20 but is currently being rejected
+  ///   because the variable declaration doesn't have an initializier.
+#if __cplusplus >= 202002L
+  constexpr int f6() {
+    int i;
+    do {
+      i = 5;
+      break;
+    } while (true);
+    return i;
+  }
+  static_assert(f6() == 5, ""); // expected-cpp20-error {{not an integral constant}}
+#endif
+
+#if 0
+  /// FIXME: This is an infinite loop, which should
+  ///   be rejected.
+  constexpr int f7() {
+    while(true);
+  }
+#endif
+};


        


More information about the cfe-commits mailing list