[clang] f18b71d - [clang][Interp] Implement remaining MaterializeTemporaryExpr bits

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 1 22:53:16 PST 2023


Author: Timm Bäder
Date: 2023-03-02T07:51:54+01:00
New Revision: f18b71d14f7efdbc76aba888fdfe233bf0de7841

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

LOG: [clang][Interp] Implement remaining MaterializeTemporaryExpr bits

As well as support for CompoundLiteralExprs.

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/test/AST/Interp/cxx17.cpp
    clang/test/AST/Interp/literals.cpp
    clang/test/AST/Interp/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index d4c9292739609..7b8253c6e193e 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -835,19 +835,10 @@ bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups(
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
     const MaterializeTemporaryExpr *E) {
-  StorageDuration SD = E->getStorageDuration();
-
-  // We conservatively only support these for now.
-  if (SD != SD_Static && SD != SD_Automatic)
-    return false;
-
   const Expr *SubExpr = E->getSubExpr();
   std::optional<PrimType> SubExprT = classify(SubExpr);
-  // FIXME: Implement this for records and arrays as well.
-  if (!SubExprT)
-    return false;
 
-  if (SD == SD_Static) {
+  if (E->getStorageDuration() == SD_Static) {
     if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
       const LifetimeExtendedTemporaryDecl *TempDecl =
           E->getLifetimeExtendedTemporaryDecl();
@@ -859,15 +850,54 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
         return false;
       return this->emitGetPtrGlobal(*GlobalIndex, E);
     }
-  } else if (SD == SD_Automatic) {
-    if (std::optional<unsigned> LocalIndex =
-            allocateLocalPrimitive(SubExpr, *SubExprT, true, true)) {
+
+    return false;
+  }
+
+  // For everyhing else, use local variables.
+  if (SubExprT) {
+    if (std::optional<unsigned> LocalIndex = allocateLocalPrimitive(
+            SubExpr, *SubExprT, /*IsMutable=*/true, /*IsExtended=*/true)) {
       if (!this->visitInitializer(SubExpr))
         return false;
+      this->emitSetLocal(*SubExprT, *LocalIndex, E);
+      return this->emitGetPtrLocal(*LocalIndex, E);
+    }
+  } else {
+    if (std::optional<unsigned> LocalIndex =
+            allocateLocal(SubExpr, /*IsExtended=*/true)) {
+      if (!this->emitGetPtrLocal(*LocalIndex, E))
+        return false;
+      return this->visitInitializer(SubExpr);
+    }
+  }
+  return false;
+}
 
-      if (!this->emitSetLocal(*SubExprT, *LocalIndex, E))
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(
+    const CompoundLiteralExpr *E) {
+  std::optional<PrimType> T = classify(E->getType());
+  const Expr *Init = E->getInitializer();
+  if (E->isFileScope()) {
+    if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
+      if (classify(E->getType()))
+        return this->visit(Init);
+      if (!this->emitGetPtrGlobal(*GlobalIndex, E))
         return false;
-      return this->emitGetPtrLocal(*LocalIndex, E);
+      return this->visitInitializer(Init);
+    }
+  }
+
+  // Otherwise, use a local variable.
+  if (T) {
+    // For primitive types, we just visit the initializer.
+    return this->visit(Init);
+  } else {
+    if (std::optional<unsigned> LocalIndex = allocateLocal(Init)) {
+      if (!this->emitGetPtrLocal(*LocalIndex, E))
+        return false;
+      return this->visitInitializer(Init);
     }
   }
 
@@ -1326,6 +1356,8 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
       }
     }
     return true;
+  } else if (const auto *CLE = dyn_cast<CompoundLiteralExpr>(Initializer)) {
+    return visitInitializer(CLE->getInitializer());
   }
 
   assert(false && "Unknown expression for array initialization");
@@ -1511,6 +1543,10 @@ bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
 
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+  // We don't know what to do with these, so just return false.
+  if (VD->getType().isNull())
+    return false;
+
   const Expr *Init = VD->getInit();
   std::optional<PrimType> VarT = classify(VD->getType());
 

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index d6390116010b4..7b804b4cad3d6 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -90,6 +90,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
   bool VisitExprWithCleanups(const ExprWithCleanups *E);
   bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
+  bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
@@ -346,7 +347,10 @@ template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
   BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
 
   void addExtended(const Scope::Local &Local) override {
-    llvm_unreachable("Cannot create temporaries in full scopes");
+    // If we to this point, just add the variable as a normal local
+    // variable. It will be destroyed at the end of the block just
+    // like all others.
+    this->addLocal(Local);
   }
 };
 
@@ -357,8 +361,8 @@ template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
   ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
 
   void addExtended(const Scope::Local &Local) override {
-    assert(this->Parent);
-    this->Parent->addLocal(Local);
+    if (this->Parent)
+      this->Parent->addLocal(Local);
   }
 };
 

diff  --git a/clang/test/AST/Interp/cxx17.cpp b/clang/test/AST/Interp/cxx17.cpp
index e72ff738ff630..e1f578a4418d9 100644
--- a/clang/test/AST/Interp/cxx17.cpp
+++ b/clang/test/AST/Interp/cxx17.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 -std=c++17 -verify=ref %s
 
 // ref-no-diagnostics
+// expected-no-diagnostics
 
 struct F { int a; int b;};
 constexpr F getF() {
@@ -21,8 +22,7 @@ constexpr int structRefs() {
 
   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}}
+static_assert(structRefs() == 15);
 
 constexpr int structRefs2() {
   F f = getF();

diff  --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 7121a24052f9a..fc36c13ed07b3 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -708,3 +708,38 @@ namespace IncDec {
   }
 };
 #endif
+
+namespace CompoundLiterals {
+  constexpr int get5() {
+    return (int[]){1,2,3,4,5}[4];
+  }
+  static_assert(get5() == 5, "");
+
+  constexpr int get6(int f = (int[]){1,2,6}[2]) { // ref-note {{subexpression not valid in a constant expression}} \
+                                                  // ref-note {{declared here}}
+    return f;
+  }
+  static_assert(get6(6) == 6, "");
+  // FIXME: Who's right here?
+  static_assert(get6() == 6, ""); // ref-error {{not an integral constant expression}}
+
+  constexpr int x = (int){3};
+  static_assert(x == 3, "");
+#if __cplusplus >= 201402L
+  constexpr int getX() {
+    int x = (int){3};
+    x = (int){5};
+    return x;
+  }
+  static_assert(getX() == 5, "");
+#endif
+
+#if __cplusplus >= 202002L
+  constexpr int get3() {
+    int m;
+    m = (int){3};
+    return m;
+  }
+  static_assert(get3() == 3, "");
+#endif
+};

diff  --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index b5bd04ff1228f..027f881f4d803 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -50,9 +50,6 @@ static_assert(ints2.a == -20, "");
 static_assert(ints2.b == -30, "");
 static_assert(!ints2.c, "");
 
-#if __cplusplus >= 201703L
-// FIXME: In c++14, this uses a MaterializeTemporaryExpr,
-//   which the new interpreter doesn't support yet.
 constexpr Ints getInts() {
   return {64, 128, true};
 }
@@ -60,7 +57,6 @@ constexpr Ints ints3 = getInts();
 static_assert(ints3.a == 64, "");
 static_assert(ints3.b == 128, "");
 static_assert(ints3.c, "");
-#endif
 
 constexpr Ints ints4 = {
   .a = 40 * 50,
@@ -88,9 +84,9 @@ struct Ints2 {
   int a = 10;
   int b;
 };
-// FIXME: Broken in the new constant interpreter.
-//   Should be rejected, but without asan errors.
-//constexpr Ints2 ints2;
+constexpr Ints2 ints22; // expected-error {{without a user-provided default constructor}} \
+                        // expected-error {{must be initialized by a constant expression}} \
+                        // ref-error {{without a user-provided default constructor}}
 
 class C {
   public:
@@ -124,9 +120,6 @@ constexpr const C* getPointer() {
 }
 static_assert(getPointer()->a == 100, "");
 
-#if __cplusplus >= 201703L
-// FIXME: In c++14, this uses a MaterializeTemporaryExpr,
-//   which the new interpreter doesn't support yet.
 constexpr C RVOAndParams(const C *c) {
   return C();
 }
@@ -137,7 +130,6 @@ constexpr C RVOAndParams(int a) {
   return C();
 }
 constexpr C RVOAndParamsResult2 = RVOAndParams(12);
-#endif
 
 class Bar { // expected-note {{definition of 'Bar' is not complete}} \
             // ref-note {{definition of 'Bar' is not complete}}
@@ -158,16 +150,16 @@ constexpr int locals() {
   c.a = 10;
 
   // Assignment, not an initializer.
-  // c = C(); FIXME
+  c = C();
   c.a = 10;
 
 
   // Assignment, not an initializer.
-  //c = RVOAndParams(&c); FIXME
+  c = RVOAndParams(&c);
 
   return c.a;
 }
-static_assert(locals() == 10, "");
+static_assert(locals() == 100, "");
 
 namespace thisPointer {
   struct S {
@@ -235,10 +227,7 @@ struct S {
     this->a; // expected-warning {{expression result unused}} \
              // ref-warning {{expression result unused}}
     get5();
-#if __cplusplus >= 201703L
-    // FIXME: Enable once we support MaterializeConstantExpr properly.
     getInts();
-#endif
   }
 
   constexpr int m() const {


        


More information about the cfe-commits mailing list