tbaeder updated this revision to Diff 551435.
tbaeder marked 6 inline comments as done.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144457/new/

https://reviews.llvm.org/D144457

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/Descriptor.h
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/Opcodes.td
  clang/lib/AST/Interp/Pointer.cpp
  clang/lib/AST/Interp/Pointer.h
  clang/lib/AST/Interp/Record.h
  clang/test/AST/Interp/records.cpp

Index: clang/test/AST/Interp/records.cpp
===================================================================
--- clang/test/AST/Interp/records.cpp
+++ clang/test/AST/Interp/records.cpp
@@ -114,6 +114,21 @@
 static_assert(c2.a == 100, "");
 static_assert(c2.b == 200, "");
 
+
+/// A global, composite temporary variable.
+constexpr const C &c3 = C().get();
+
+/// Same, but with a bitfield.
+class D {
+public:
+  unsigned a : 4;
+  constexpr D() : a(15) {}
+  constexpr D get() const {
+    return *this;
+  }
+};
+constexpr const D &d4 = D().get();
+
 constexpr int getB() {
   C c;
   int &j = c.b;
Index: clang/lib/AST/Interp/Record.h
===================================================================
--- clang/lib/AST/Interp/Record.h
+++ clang/lib/AST/Interp/Record.h
@@ -88,7 +88,10 @@
   }
 
   unsigned getNumBases() const { return Bases.size(); }
-  const Base *getBase(unsigned I) const { return &Bases[I]; }
+  const Base *getBase(unsigned I) const {
+    assert(I < getNumBases());
+    return &Bases[I];
+  }
 
   using const_virtual_iter = VirtualBaseList::const_iterator;
   llvm::iterator_range<const_virtual_iter> virtual_bases() const {
Index: clang/lib/AST/Interp/Pointer.h
===================================================================
--- clang/lib/AST/Interp/Pointer.h
+++ clang/lib/AST/Interp/Pointer.h
@@ -27,6 +27,7 @@
 class Block;
 class DeadBlock;
 class Pointer;
+class Context;
 enum PrimType : unsigned;
 
 class Pointer;
@@ -87,6 +88,9 @@
     return reinterpret_cast<uintptr_t>(Pointee) + Offset;
   }
 
+  /// Converts the pointer to an APValue that is an rvalue.
+  APValue toRValue(const Context &Ctx) const;
+
   /// Offsets a pointer inside an array.
   Pointer atIndex(unsigned Idx) const {
     if (Base == RootPtrMark)
Index: clang/lib/AST/Interp/Pointer.cpp
===================================================================
--- clang/lib/AST/Interp/Pointer.cpp
+++ clang/lib/AST/Interp/Pointer.cpp
@@ -7,9 +7,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "Pointer.h"
+#include "Boolean.h"
+#include "Context.h"
+#include "Floating.h"
 #include "Function.h"
+#include "Integral.h"
 #include "InterpBlock.h"
 #include "PrimType.h"
+#include "Record.h"
 
 using namespace clang;
 using namespace clang::interp;
@@ -217,3 +222,34 @@
 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
   return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
 }
+
+APValue Pointer::toRValue(const Context &Ctx) const {
+  // Primitives.
+  if (getFieldDesc()->isPrimitive()) {
+    PrimType PT = *Ctx.classify(getType());
+    TYPE_SWITCH(PT, return deref<T>().toAPValue());
+    llvm_unreachable("Unhandled PrimType?");
+  }
+
+  APValue Result;
+  // Records.
+  if (getFieldDesc()->isRecord()) {
+    const Record *R = getRecord();
+    Result =
+        APValue(APValue::UninitStruct(), R->getNumBases(), R->getNumFields());
+
+    for (unsigned I = 0; I != R->getNumFields(); ++I) {
+      const Pointer &FieldPtr = this->atField(R->getField(I)->Offset);
+      Result.getStructField(I) = FieldPtr.toRValue(Ctx);
+    }
+
+    for (unsigned I = 0; I != R->getNumBases(); ++I) {
+      const Pointer &BasePtr = this->atField(R->getBase(I)->Offset);
+      Result.getStructBase(I) = BasePtr.toRValue(Ctx);
+    }
+  }
+
+  // TODO: Arrays
+
+  return Result;
+}
Index: clang/lib/AST/Interp/Opcodes.td
===================================================================
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -353,6 +353,12 @@
 def InitGlobalTemp : AccessOpcode {
   let Args = [ArgUint32, ArgLETD];
 }
+// [Pointer] -> [Pointer]
+def InitGlobalTempComp : Opcode {
+  let Args = [ArgLETD];
+  let Types = [];
+  let HasGroup = 0;
+}
 // [Value] -> []
 def SetGlobal : AccessOpcode;
 
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -993,6 +993,19 @@
   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
+inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
+                               const LifetimeExtendedTemporaryDecl *Temp) {
+  assert(Temp);
+  const Pointer &P = S.Stk.peek<Pointer>();
+  APValue *Cached = Temp->getOrCreateValue(true);
+
+  *Cached = P.toRValue(S.getCtx());
+  return true;
+}
+
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
   if (S.checkingPotentialConstantExpression())
Index: clang/lib/AST/Interp/Descriptor.h
===================================================================
--- clang/lib/AST/Interp/Descriptor.h
+++ clang/lib/AST/Interp/Descriptor.h
@@ -187,6 +187,8 @@
 
   /// Checks if the descriptor is of an array.
   bool isArray() const { return IsArray; }
+  /// Checks if the descriptor is of a record.
+  bool isRecord() const { return !IsArray && ElemRecord; }
 };
 
 /// Bitfield tracking the initialisation status of elements of primitive arrays.
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -893,19 +893,28 @@
     return this->discard(SubExpr);
 
   if (E->getStorageDuration() == SD_Static) {
-    if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
-      const LifetimeExtendedTemporaryDecl *TempDecl =
-          E->getLifetimeExtendedTemporaryDecl();
+    std::optional<unsigned> GlobalIndex = P.createGlobal(E);
+    if (!GlobalIndex)
+      return false;
+
+    const LifetimeExtendedTemporaryDecl *TempDecl =
+        E->getLifetimeExtendedTemporaryDecl();
+    assert(TempDecl);
 
+    if (SubExprT) {
       if (!this->visitInitializer(SubExpr))
         return false;
-
       if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
         return false;
       return this->emitGetPtrGlobal(*GlobalIndex, E);
     }
 
-    return false;
+    // Non-primitive values.
+    if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+      return false;
+    if (!this->visitInitializer(SubExpr))
+      return false;
+    return this->emitInitGlobalTempComp(TempDecl, E);
   }
 
   // For everyhing else, use local variables.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to