diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 79d44842d8319..49f9878d42480 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -3009,21 +3009,53 @@ bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { // pointer to the actual value) instead of a pointer to the pointer to the // value. bool IsReference = D->getType()->isReferenceType(); + // Complex values are copied in the AST via a simply assignment or + // ltor cast. But we represent them as two-element arrays, which means + // we pass them around as pointers. So, to assignm from them, we will + // have to copy both (primitive) elements instead. + bool IsComplex = D->getType()->isAnyComplexType(); // Check for local/global variables and parameters. if (auto It = Locals.find(D); It != Locals.end()) { const unsigned Offset = It->second.Offset; + // FIXME: Fix the code duplication here with the code in the global case. + if (Initializing && IsComplex) { + PrimType ElemT = classifyComplexElementType(D->getType()); + for (unsigned I = 0; I != 2; ++I) { + if (!this->emitGetPtrLocal(Offset, E)) + return false; + if (!this->emitArrayElemPop(ElemT, I, E)) + return false; + if (!this->emitInitElem(ElemT, I, E)) + return false; + } + return true; + } if (IsReference) return this->emitGetLocal(PT_Ptr, Offset, E); return this->emitGetPtrLocal(Offset, E); } else if (auto GlobalIndex = P.getGlobal(D)) { + if (Initializing && IsComplex) { + PrimType ElemT = classifyComplexElementType(D->getType()); + for (unsigned I = 0; I != 2; ++I) { + if (!this->emitGetPtrGlobal(*GlobalIndex, E)) + return false; + if (!this->emitArrayElemPop(ElemT, I, E)) + return false; + if (!this->emitInitElem(ElemT, I, E)) + return false; + } + return true; + } + if (IsReference) return this->emitGetGlobalPtr(*GlobalIndex, E); return this->emitGetPtrGlobal(*GlobalIndex, E); } else if (const auto *PVD = dyn_cast(D)) { if (auto It = this->Params.find(PVD); It != this->Params.end()) { + // FIXME: _Complex initializing case? if (IsReference || !It->second.IsPtr) return this->emitGetParamPtr(It->second.Offset, E); diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index b33cf55c61f03..a76e63395157f 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1878,6 +1878,14 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { return NarrowPtr(S, OpPC); } +template ::T> +inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) { + const Pointer &Ptr = S.Stk.pop(); + + S.Stk.push(Ptr.atIndex(Index).deref()); + return true; +} + /// Just takes a pointer and checks if it's an incomplete /// array type. inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index e720b95498f17..7f5bd7e5b44bc 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -357,6 +357,12 @@ def ExpandPtr : Opcode; def ArrayElemPtr : AluOpcode; def ArrayElemPtrPop : AluOpcode; +def ArrayElemPop : Opcode { + let Args = [ArgUint32]; + let Types = [AllTypeClass]; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Direct field accessors //===----------------------------------------------------------------------===// diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index 7f02bfa18bbdb..20c00b8e1ba3f 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -194,3 +194,21 @@ namespace ZeroInit { constexpr int ignored = (fcomplex(), 0); } + +namespace DeclRefCopy { + constexpr _Complex int ComplexInt = 42 + 24i; + + constexpr _Complex int B = ComplexInt; + constexpr _Complex int ArrayOfComplexInt[4] = {ComplexInt, ComplexInt, ComplexInt, ComplexInt}; + static_assert(__real(ArrayOfComplexInt[0]) == 42, ""); + static_assert(__imag(ArrayOfComplexInt[0]) == 24, ""); + static_assert(__real(ArrayOfComplexInt[3]) == 42, ""); + static_assert(__imag(ArrayOfComplexInt[3]) == 24, ""); + + constexpr int localComplexArray() { + _Complex int A = 42 + 24i; + _Complex int ArrayOfComplexInt[4] = {A, A, A, A}; + return __real(ArrayOfComplexInt[0]) + __imag(ArrayOfComplexInt[3]); + } + static_assert(localComplexArray() == (24 + 42), ""); +}