tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, shafik, tahonermann.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

I was wondering whether it is somehow possible to get a loop into a expression 
so I can use it directly in a `static_assert()` (and it would be interpreted 
directly rather than compiled to bytecode).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D135433

Files:
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/ByteCodeStmtGen.h
  clang/test/AST/Interp/loops.cpp

Index: clang/test/AST/Interp/loops.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/loops.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify=ref %s
+
+// expected-no-diagnostics
+// ref-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, "");
+};
+
+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, "");
+};
Index: clang/lib/AST/Interp/ByteCodeStmtGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeStmtGen.h
+++ clang/lib/AST/Interp/ByteCodeStmtGen.h
@@ -58,6 +58,8 @@
   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);
 
   /// Compiles a variable declaration.
   bool visitVarDecl(const VarDecl *VD);
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -167,6 +167,10 @@
     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::NullStmtClass:
     return true;
   default: {
@@ -276,6 +280,47 @@
   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
+
+  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();
+
+  this->emitLabel(StartLabel);
+  if (!this->visitStmt(Body))
+    return false;
+  if (!this->visitBool(Cond))
+    return false;
+  if (!this->jumpTrue(StartLabel))
+    return false;
+  return true;
+}
+
 template <class Emitter>
 bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
   if (!VD->hasLocalStorage()) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to