[clang] 7bb615e - [clang][Interp] Materializing primitive temporaries

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 3 06:11:34 PST 2023


Author: Timm Bäder
Date: 2023-02-03T15:11:15+01:00
New Revision: 7bb615ea0ec015eb5991ddc00e0a3fc31cb2735e

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

LOG: [clang][Interp] Materializing primitive temporaries

Implement MaterializeTemporaryExpr for primitive types.

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Opcodes.td
    clang/test/AST/Interp/references.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 4c3b6f59a3016..b02e3ae02ae7c 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -782,6 +782,57 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
   return this->emitStore(*ResultT, E);
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups(
+    const ExprWithCleanups *E) {
+  const Expr *SubExpr = E->getSubExpr();
+
+  assert(E->getNumObjects() == 0 && "TODO: Implement cleanups");
+  return this->visit(SubExpr);
+}
+
+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 (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
+      const LifetimeExtendedTemporaryDecl *TempDecl =
+          E->getLifetimeExtendedTemporaryDecl();
+
+      if (!this->visitInitializer(SubExpr))
+        return false;
+
+      if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
+        return false;
+      return this->emitGetPtrGlobal(*GlobalIndex, E);
+    }
+  } else if (SD == SD_Automatic) {
+    if (std::optional<unsigned> LocalIndex =
+            allocateLocalPrimitive(SubExpr, *SubExprT, true, true)) {
+      if (!this->visitInitializer(SubExpr))
+        return false;
+
+      if (!this->emitSetLocal(*SubExprT, *LocalIndex, E))
+        return false;
+      return this->emitGetPtrLocal(*LocalIndex, E);
+    }
+  }
+
+  return false;
+}
+
 template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
   if (E->containsErrors())
     return false;

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 0a64ff3513dd8..540b9ec2f3d46 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -87,6 +87,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitCharacterLiteral(const CharacterLiteral *E);
   bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
   bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);
+  bool VisitExprWithCleanups(const ExprWithCleanups *E);
+  bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index b35cc017d3d70..99c1bd58acd25 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -818,6 +818,22 @@ bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
   return true;
 }
 
+/// 1) Converts the value on top of the stack to an APValue
+/// 2) Sets that APValue on \Temp
+/// 3) Initialized global with index \I with that
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
+                    const LifetimeExtendedTemporaryDecl *Temp) {
+  assert(Temp);
+  const T Value = S.Stk.peek<T>();
+  APValue APV = Value.toAPValue();
+  APValue *Cached = Temp->getOrCreateValue(true);
+  *Cached = APV;
+
+  S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
+  return true;
+}
+
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
   if (S.checkingPotentialConstantExpression())

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 8b49fb4e61b1b..d1ad7adc1edc6 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -49,6 +49,7 @@ def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
 def ArgRecordField : ArgType { let Name = "const Record::Field *"; }
 def ArgFltSemantics : ArgType { let Name = "const llvm::fltSemantics *"; }
 def ArgRoundingMode : ArgType { let Name = "llvm::RoundingMode"; }
+def ArgLETD: ArgType { let Name = "const LifetimeExtendedTemporaryDecl *"; }
 
 //===----------------------------------------------------------------------===//
 // Classes of types instructions operate on.
@@ -332,6 +333,10 @@ def GetGlobal : AccessOpcode;
 // [Value] -> []
 def InitGlobal : AccessOpcode;
 // [Value] -> []
+def InitGlobalTemp : AccessOpcode {
+  let Args = [ArgUint32, ArgLETD];
+}
+// [Value] -> []
 def SetGlobal : AccessOpcode;
 
 // [] -> [Value]

diff  --git a/clang/test/AST/Interp/references.cpp b/clang/test/AST/Interp/references.cpp
index 0e6d5532ba0e8..5dc6067db6a64 100644
--- a/clang/test/AST/Interp/references.cpp
+++ b/clang/test/AST/Interp/references.cpp
@@ -2,8 +2,6 @@
 // RUN: %clang_cc1 -verify=ref %s
 
 
-// ref-no-diagnostics
-
 constexpr int a = 10;
 constexpr const int &b = a;
 static_assert(a == b, "");
@@ -71,9 +69,22 @@ constexpr int testGetValue() {
 }
 static_assert(testGetValue() == 30, "");
 
-// FIXME: ExprWithCleanups + MaterializeTemporaryExpr not implemented
-constexpr const int &MCE = 1; // expected-error{{must be initialized by a constant expression}}
+constexpr const int &MCE = 20;
+static_assert(MCE == 20, "");
+static_assert(MCE == 30, ""); // expected-error {{static assertion failed}} \
+                              // expected-note {{evaluates to '20 == 30'}} \
+                              // ref-error {{static assertion failed}} \
+                              // ref-note {{evaluates to '20 == 30'}}
 
+constexpr int LocalMCE() {
+  const int &m = 100;
+  return m;
+}
+static_assert(LocalMCE() == 100, "");
+static_assert(LocalMCE() == 200, ""); // expected-error {{static assertion failed}} \
+                                      // expected-note {{evaluates to '100 == 200'}} \
+                                      // ref-error {{static assertion failed}} \
+                                      // ref-note {{evaluates to '100 == 200'}}
 
 struct S {
   int i, j;


        


More information about the cfe-commits mailing list