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

Factor out the actual variable allocation logic into a separate function, so we 
can call it multiple times from `visitVarDecl()` if the variable declaration is 
a `DecompositionDecl()`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D138802

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/ByteCodeStmtGen.cpp
  clang/lib/AST/Interp/Program.h
  clang/test/AST/Interp/cxx17.cpp

Index: clang/test/AST/Interp/cxx17.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/cxx17.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify=ref %s
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+struct F { int a; int b;};
+constexpr F getF() {
+  return {12, 3};
+}
+constexpr int f() {
+  auto [a1, b1] = getF();
+  auto [a2, b2] = getF();
+
+  return a1 + a2 + b1 + b2;
+}
+static_assert(f() == 30);
+
+
+constexpr int a() {
+  int a[2] = {5, 3};
+  auto [x, y] = a;
+  return x + y;
+}
+static_assert(a() == 8);
+
Index: clang/lib/AST/Interp/Program.h
===================================================================
--- clang/lib/AST/Interp/Program.h
+++ clang/lib/AST/Interp/Program.h
@@ -131,7 +131,9 @@
   /// Context to manage declaration lifetimes.
   class DeclScope {
   public:
-    DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
+    DeclScope(Program &P, const ValueDecl *VD) : P(P) {
+      P.startDeclaration(VD);
+    }
     ~DeclScope() { P.endDeclaration(); }
 
   private:
@@ -222,7 +224,7 @@
   unsigned CurrentDeclaration = NoDeclaration;
 
   /// Starts evaluating a declaration.
-  void startDeclaration(const VarDecl *Decl) {
+  void startDeclaration(const ValueDecl *Decl) {
     LastDeclaration += 1;
     CurrentDeclaration = LastDeclaration;
   }
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -211,17 +211,11 @@
 template <class Emitter>
 bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
   for (auto *D : DS->decls()) {
-    // Variable declarator.
-    if (auto *VD = dyn_cast<VarDecl>(D)) {
-      if (!this->visitVarDecl(VD))
-        return false;
-      continue;
-    }
-
-    // Decomposition declarator.
-    if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
-      return this->bail(DD);
-    }
+    const auto *VD = dyn_cast<VarDecl>(D);
+    if (!VD)
+      return false;
+    if (!this->visitVarDecl(VD))
+      return false;
   }
 
   return true;
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -97,6 +97,8 @@
   bool visitDecl(const VarDecl *VD) override;
   bool visitVarDecl(const VarDecl *VD);
 
+  bool allocateVariable(const ValueDecl *VD, const Expr *Init);
+
   /// Emits scope cleanup instructions.
   void emitCleanup();
 
@@ -287,8 +289,11 @@
 
   /// Returns whether we should create a global variable for the
   /// given VarDecl.
-  bool isGlobalDecl(const VarDecl *VD) const {
-    return !VD->hasLocalStorage() || VD->isConstexpr();
+  bool isGlobalDecl(const ValueDecl *VD) const {
+    if (const auto *V = dyn_cast<VarDecl>(VD))
+      return !V->hasLocalStorage() || V->isConstexpr();
+
+    return false;
   }
 };
 
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -29,7 +29,7 @@
 /// Scope used to handle temporaries in toplevel variable declarations.
 template <class Emitter> class DeclScope final : public VariableScope<Emitter> {
 public:
-  DeclScope(ByteCodeExprGen<Emitter> *Ctx, const VarDecl *VD)
+  DeclScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
       : VariableScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
 
   virtual ~DeclScope() override { this->emitDestruction(); }
@@ -796,14 +796,15 @@
 bool ByteCodeExprGen<Emitter>::dereference(
     const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
     llvm::function_ref<bool(PrimType)> Indirect) {
+
   if (Optional<PrimType> T = classify(LV->getType())) {
     if (!LV->refersToBitField()) {
       // Only primitive, non bit-field types can be dereferenced directly.
-      if (auto *DE = dyn_cast<DeclRefExpr>(LV)) {
+      if (const auto *DE = dyn_cast<DeclRefExpr>(LV)) {
         if (!DE->getDecl()->getType()->isReferenceType()) {
-          if (auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
+          if (const auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
             return dereferenceParam(LV, *T, PD, AK, Direct, Indirect);
-          if (auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
+          if (const auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
             return dereferenceVar(LV, *T, VD, AK, Direct, Indirect);
         }
       }
@@ -1379,8 +1380,8 @@
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
-  const Expr *Init = VD->getInit();
+bool ByteCodeExprGen<Emitter>::allocateVariable(const ValueDecl *VD,
+                                                const Expr *Init) {
   Optional<PrimType> VarT = classify(VD->getType());
 
   if (isGlobalDecl(VD)) {
@@ -1411,6 +1412,14 @@
         if (!this->visit(Init))
           return false;
 
+        // Initializers are supposed to be rvalues. However, sometimes
+        // they aren't. This is the case for C++ decomposition decl
+        // bindings.
+        if (Init && Init->isLValue() && *VarT != PT_Ptr) {
+          if (!this->emitLoadPop(*VarT, VD))
+            return false;
+        }
+
         return this->emitSetLocal(*VarT, Offset, VD);
       }
     } else {
@@ -1425,6 +1434,29 @@
   return false;
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+  // For decomposition decls, we just emit multiple variables.
+  if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
+    // Expression to decompose.
+    const Expr *Init = DD->getInit();
+
+    if (!this->allocateVariable(DD, Init))
+      return false;
+
+    for (const auto *BD : DD->bindings()) {
+      assert(!BD->getHoldingVar()); // FIXME
+      if (!this->allocateVariable(BD, BD->getBinding()))
+        return false;
+    }
+
+    return true;
+  }
+
+  // Regular variables.
+  return this->allocateVariable(VD, VD->getInit());
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
   const Decl *Callee = E->getCalleeDecl();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to