Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -139,6 +139,7 @@ bool visitArrayInitializer(const Expr *Initializer); /// Compiles a record initializer. bool visitRecordInitializer(const Expr *Initializer); + bool visitComplexInitializer(const Expr *Initializer); /// Creates and initializes a variable from the given decl. bool visitVarDecl(const VarDecl *VD); Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1573,6 +1573,33 @@ return false; } +/// Visit an initializer for a _Complex type. +/// They are represented as two-element arrays. +template +bool ByteCodeExprGen::visitComplexInitializer( + const Expr *Initializer) { + if (const auto *InitList = dyn_cast(Initializer)) { + unsigned InitIndex = 0; + for (const Expr *Init : InitList->inits()) { + PrimType InitT = classifyPrim(Init->getType()); + + if (!this->visit(Init)) + return false; + + if (!this->emitInitElem(InitT, InitIndex, InitList)) + return false; + ++InitIndex; + } + assert(InitIndex == 2); + return true; + } else if (const auto *CE = dyn_cast(Initializer)) { + if (!this->emitDupPtr(Initializer)) + return false; + return this->visit(CE); + } + return false; +} + template bool ByteCodeExprGen::visitInitializer(const Expr *Initializer) { QualType InitializerType = Initializer->getType(); @@ -1583,6 +1610,9 @@ if (InitializerType->isRecordType()) return visitRecordInitializer(Initializer); + if (InitializerType->isAnyComplexType()) + return visitComplexInitializer(Initializer); + // Otherwise, visit the expression like normal. return this->visit(Initializer); } @@ -1983,8 +2013,22 @@ if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E); - case UO_Real: // __real x - case UO_Imag: // __imag x + case UO_Real: { // __real x + assert(!T); + if (!this->visit(SubExpr)) + return false; + if (!this->emitConstUint8(0, E)) + return false; + return this->emitArrayElemPtrPopUint8(E); + } + case UO_Imag: { // __imag x + assert(!T); + if (!this->visit(SubExpr)) + return false; + if (!this->emitConstUint8(1, E)) + return false; + return this->emitArrayElemPtrPopUint8(E); + } case UO_Extension: case UO_Coawait: assert(false && "Unhandled opcode"); Index: clang/lib/AST/Interp/Context.cpp =================================================================== --- clang/lib/AST/Interp/Context.cpp +++ clang/lib/AST/Interp/Context.cpp @@ -81,6 +81,9 @@ if (T->isBooleanType()) return PT_Bool; + if (T->isAnyComplexType()) + return std::nullopt; + if (T->isSignedIntegerOrEnumerationType()) { switch (Ctx.getIntWidth(T)) { case 64: Index: clang/lib/AST/Interp/EvalEmitter.cpp =================================================================== --- clang/lib/AST/Interp/EvalEmitter.cpp +++ clang/lib/AST/Interp/EvalEmitter.cpp @@ -196,6 +196,27 @@ } return Ok; } + + // Complex types. + if (const auto *CT = Ty->getAs()) { + QualType ElemTy = CT->getElementType(); + std::optional ElemT = Ctx.classify(ElemTy); + assert(ElemT); + + if (ElemTy->isIntegerType()) { + INT_TYPE_SWITCH(*ElemT, { + auto V1 = Ptr.atIndex(0).deref(); + auto V2 = Ptr.atIndex(1).deref(); + Result = APValue(V1.toAPSInt(), V2.toAPSInt()); + return true; + }); + } else if (ElemTy->isFloatingType()) { + Result = APValue(Ptr.atIndex(0).deref().getAPFloat(), + Ptr.atIndex(1).deref().getAPFloat()); + return true; + } + return false; + } llvm_unreachable("invalid value to return"); }; Index: clang/lib/AST/Interp/PrimType.h =================================================================== --- clang/lib/AST/Interp/PrimType.h +++ clang/lib/AST/Interp/PrimType.h @@ -102,6 +102,22 @@ } \ } while (0) +#define INT_TYPE_SWITCH(Expr, B) \ + do { \ + switch (Expr) { \ + TYPE_SWITCH_CASE(PT_Sint8, B) \ + TYPE_SWITCH_CASE(PT_Uint8, B) \ + TYPE_SWITCH_CASE(PT_Sint16, B) \ + TYPE_SWITCH_CASE(PT_Uint16, B) \ + TYPE_SWITCH_CASE(PT_Sint32, B) \ + TYPE_SWITCH_CASE(PT_Uint32, B) \ + TYPE_SWITCH_CASE(PT_Sint64, B) \ + TYPE_SWITCH_CASE(PT_Uint64, B) \ + default: \ + llvm_unreachable("Unhandled integer type"); \ + } \ + } while (0) + #define BITCAST_TYPE_SWITCH(Expr, B) \ do { \ switch (Expr) { \ Index: clang/test/AST/Interp/complex.cpp =================================================================== --- /dev/null +++ clang/test/AST/Interp/complex.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s +// RUN: %clang_cc1 -verify=ref %s + +// expected-no-diagnostics +// ref-no-diagnostics + +constexpr _Complex double z1 = {1.0, 2.0}; +static_assert(__real(z1) == 1.0, ""); +static_assert(__imag(z1) == 2.0, ""); + +constexpr double setter() { + _Complex float d = {1.0, 2.0}; + + __imag(d) = 4.0; + return __imag(d); +} +static_assert(setter() == 4, ""); + +constexpr _Complex double getter() { + return {1.0, 3.0}; +} +constexpr _Complex double D = getter(); +static_assert(__real(D) == 1.0, ""); +static_assert(__imag(D) == 3.0, ""); + + +constexpr _Complex int I1 = {1, 2}; +static_assert(__real(I1) == 1, ""); +static_assert(__imag(I1) == 2, "");