Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -833,12 +833,12 @@ if (!GlobalIndex) return false; + const LifetimeExtendedTemporaryDecl *TempDecl = + E->getLifetimeExtendedTemporaryDecl(); + if (SubExprT) { if (!this->visitInitializer(SubExpr)) return false; - - const LifetimeExtendedTemporaryDecl *TempDecl = - E->getLifetimeExtendedTemporaryDecl(); if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E)) return false; return this->emitGetPtrGlobal(*GlobalIndex, E); @@ -847,7 +847,9 @@ // Non-primitive values. if (!this->emitGetPtrGlobal(*GlobalIndex, E)) return false; - return this->visitInitializer(SubExpr); + if (!this->visitInitializer(SubExpr)) + return false; + return this->emitInitGlobalTempComp(TempDecl, E); } // For everyhing else, use local variables. Index: clang/lib/AST/Interp/Descriptor.h =================================================================== --- clang/lib/AST/Interp/Descriptor.h +++ clang/lib/AST/Interp/Descriptor.h @@ -184,6 +184,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/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -835,6 +835,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(); + APValue *Cached = Temp->getOrCreateValue(true); + + *Cached = P.toRValue(S.getCtx()); + return true; +} + template ::T> bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { if (S.checkingPotentialConstantExpression()) Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -351,6 +351,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/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; /// A pointer to a memory block, live or dead. @@ -78,6 +79,9 @@ /// Converts the pointer to an APValue. APValue toAPValue() const; + /// 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 (!Pointee) 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; @@ -211,3 +216,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().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/Record.h =================================================================== --- clang/lib/AST/Interp/Record.h +++ clang/lib/AST/Interp/Record.h @@ -87,6 +87,7 @@ } unsigned getNumBases() const { return Bases.size(); } + const Base *getBase(unsigned I) const { return &Bases[I]; } Base *getBase(unsigned I) { return &Bases[I]; } using const_virtual_iter = VirtualBaseList::const_iterator; Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -114,6 +114,9 @@ static_assert(c.a == 100, ""); static_assert(c.b == 200, ""); + +constexpr const C &c3 = C().get(); + constexpr int getB() { C c; int &j = c.b;