diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 386abef598594..c4598151f95d6 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -311,6 +311,63 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitInitElem(T, 1, SubExpr); } + case CK_IntegralComplexCast: + case CK_FloatingComplexCast: + case CK_IntegralComplexToFloatingComplex: + case CK_FloatingComplexToIntegralComplex: { + assert(CE->getType()->isAnyComplexType()); + assert(SubExpr->getType()->isAnyComplexType()); + if (DiscardResult) + return this->discard(SubExpr); + + if (!Initializing) { + std::optional LocalIndex = + allocateLocal(CE, /*IsExtended=*/true); + if (!LocalIndex) + return false; + if (!this->emitGetPtrLocal(*LocalIndex, CE)) + return false; + } + + // Location for the SubExpr. + // Since SubExpr is of complex type, visiting it results in a pointer + // anyway, so we just create a temporary pointer variable. + std::optional SubExprOffset = allocateLocalPrimitive( + SubExpr, PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false); + if (!SubExprOffset) + return false; + + if (!this->visit(SubExpr)) + return false; + if (!this->emitSetLocal(PT_Ptr, *SubExprOffset, CE)) + return false; + + PrimType SourceElemT = *classifyComplexElementType(SubExpr->getType()); + QualType DestElemType = + CE->getType()->getAs()->getElementType(); + PrimType DestElemT = classifyPrim(DestElemType); + // Cast both elements individually. + for (unsigned I = 0; I != 2; ++I) { + if (!this->emitGetLocal(PT_Ptr, *SubExprOffset, CE)) + return false; + if (!this->emitConstUint8(I, CE)) + return false; + if (!this->emitArrayElemPtrPopUint8(CE)) + return false; + if (!this->emitLoadPop(SourceElemT, CE)) + return false; + + // Do the cast. + if (!this->emitPrimCast(SourceElemT, DestElemT, DestElemType, CE)) + return false; + + // Save the value. + if (!this->emitInitElem(DestElemT, I, CE)) + return false; + } + return true; + } + case CK_ToVoid: return discard(SubExpr); diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 7ae4617f28137..53b89c51b5a81 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -238,8 +238,14 @@ class Pointer { /// Returns the type of the innermost field. QualType getType() const { - if (inPrimitiveArray() && Offset != Base) - return getFieldDesc()->getType()->getAsArrayTypeUnsafe()->getElementType(); + if (inPrimitiveArray() && Offset != Base) { + // Unfortunately, complex types are not array types in clang, but they are + // for us. + if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) + return AT->getElementType(); + if (const auto *CT = getFieldDesc()->getType()->getAs()) + return CT->getElementType(); + } return getFieldDesc()->getType(); } diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index 836ea552adac8..8c57df7d9a3ed 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -47,16 +47,31 @@ static_assert(__real(12u) == 12u, ""); static_assert(__imag(4.0) == 0.0, ""); static_assert(__imag(13) == 0, ""); -constexpr int ignoredCast() { + +constexpr _Complex long L1 = D; +static_assert(__real(L1) == 1.0, ""); +static_assert(__imag(L1) == 3.0, ""); + +constexpr _Complex short I4 = L1; +static_assert(__real(I4) == 1, ""); +static_assert(__imag(I4) == 3, ""); + +constexpr _Complex float D3 = D; +static_assert(__real(D3) == 1.0, ""); +static_assert(__imag(D3) == 3.0, ""); + + +constexpr int ignored() { I2; (int)I2; (float)I2; D1; (int)D1; (double)D1; + (_Complex float)I2; return 0; } -static_assert(ignoredCast() == 0, ""); +static_assert(ignored() == 0, ""); static_assert((int)I1 == 1, ""); static_assert((float)D == 1.0f, "");