[clang] 730eca6 - [clang][Interp] Handle DecompositionDecls

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 1 08:12:10 PST 2023


Author: Timm Bäder
Date: 2023-03-01T17:11:57+01:00
New Revision: 730eca6a3de85ae66bb905ee32c47332b5395226

URL: https://github.com/llvm/llvm-project/commit/730eca6a3de85ae66bb905ee32c47332b5395226
DIFF: https://github.com/llvm/llvm-project/commit/730eca6a3de85ae66bb905ee32c47332b5395226.diff

LOG: [clang][Interp] Handle DecompositionDecls

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

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

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

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 2b4e324f7b0fa..d4c9292739609 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -28,7 +28,7 @@ namespace interp {
 /// Scope used to handle temporaries in toplevel variable declarations.
 template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
 public:
-  DeclScope(ByteCodeExprGen<Emitter> *Ctx, const VarDecl *VD)
+  DeclScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
       : LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
 
   void addExtended(const Scope::Local &Local) override {
@@ -936,11 +936,11 @@ bool ByteCodeExprGen<Emitter>::dereference(
   if (std::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);
         }
       }
@@ -1823,6 +1823,8 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
     }
   } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(Decl)) {
     return this->emitConst(ECD->getInitVal(), E);
+  } else if (const auto *BD = dyn_cast<BindingDecl>(Decl)) {
+    return this->visit(BD->getBinding());
   }
 
   return false;

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 74cd5984daf55..d6390116010b4 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -235,9 +235,12 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   }
 
   /// Returns whether we should create a global variable for the
-  /// given VarDecl.
-  bool shouldBeGloballyIndexed(const VarDecl *VD) const {
-    return VD->hasGlobalStorage() || VD->isConstexpr();
+  /// given ValueDecl.
+  bool shouldBeGloballyIndexed(const ValueDecl *VD) const {
+    if (const auto *V = dyn_cast<VarDecl>(VD))
+      return V->hasGlobalStorage() || V->isConstexpr();
+
+    return false;
   }
 
   llvm::RoundingMode getRoundingMode(const Expr *E) const {

diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 522b04254e85d..ff2727cc4d354 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -205,17 +205,11 @@ bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
 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;

diff  --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h
index 5a80dd1ed748e..4547ca7ac69c1 100644
--- a/clang/lib/AST/Interp/Program.h
+++ b/clang/lib/AST/Interp/Program.h
@@ -131,7 +131,9 @@ class Program final {
   /// 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 @@ class Program final {
   unsigned CurrentDeclaration = NoDeclaration;
 
   /// Starts evaluating a declaration.
-  void startDeclaration(const VarDecl *Decl) {
+  void startDeclaration(const ValueDecl *Decl) {
     LastDeclaration += 1;
     CurrentDeclaration = LastDeclaration;
   }

diff  --git a/clang/test/AST/Interp/cxx17.cpp b/clang/test/AST/Interp/cxx17.cpp
new file mode 100644
index 0000000000000..e72ff738ff630
--- /dev/null
+++ b/clang/test/AST/Interp/cxx17.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify=ref %s
+
+// 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 structRefs() {
+  const auto &[a, b] = getF();
+
+  return a + b;
+}
+// FIXME: This should work, but the MaterializeTemporaryExpr handling is not ready for it.
+static_assert(structRefs() == 15); // expected-error {{not an integral constant expression}}
+
+constexpr int structRefs2() {
+  F f = getF();
+  const auto &[a, b] = f;
+
+  return a + b;
+}
+static_assert(structRefs2() == 15);
+
+
+template<typename T>
+struct Tuple {
+  T first;
+  T second;
+  constexpr Tuple(T a, T b) : first(a), second(b) {}
+};
+template<typename T>
+constexpr T addTuple(const Tuple<T> &Tu) {
+  auto [a, b] = Tu;
+  return a + b;
+}
+
+template<typename T>
+constexpr T addTuple2(const Tuple<T> &Tu) {
+  auto [a, b] = Tu;
+  return Tu.first + Tu.second;
+}
+
+constexpr Tuple<int> T1 = Tuple(1,2);
+static_assert(addTuple(T1) == 3);
+static_assert(addTuple2(T1) == 3);
+
+constexpr Tuple<short> T2 = Tuple<short>(11,2);
+static_assert(addTuple(T2) == 13);
+static_assert(addTuple2(T2) == 13);
+
+constexpr int Modify() {
+  auto T = Tuple<int>(10, 20);
+  auto &[x, y] = T;
+  x += 1;
+  y += 1;
+  return T.first + T.second;
+}
+static_assert(Modify() == 32, "");
+
+constexpr int a() {
+  int a[2] = {5, 3};
+  auto [x, y] = a;
+  return x + y;
+}
+static_assert(a() == 8);
+
+constexpr int b() {
+  int a[2] = {5, 3};
+  auto &[x, y] = a;
+  x += 1;
+  y += 2;
+  return a[0] + a[1];
+}
+static_assert(b() == 11);


        


More information about the cfe-commits mailing list