diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index a4a00ddab6503..c428446386c04 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -222,6 +222,52 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitNE(PtrT, CE); } + case CK_IntegralComplexToBoolean: { + std::optional ElemT = + classifyComplexElementType(SubExpr->getType()); + if (!ElemT) + return false; + // We emit the expression (__real(E) != 0 || __imag(E) != 0) + // for us, that means (bool)E[0] || (bool)E[1] + if (!this->visit(SubExpr)) + return false; + if (!this->emitConstUint8(0, CE)) + return false; + if (!this->emitArrayElemPtrUint8(CE)) + return false; + if (!this->emitLoadPop(*ElemT, CE)) + return false; + if (!this->emitCast(*ElemT, PT_Bool, CE)) + return false; + // We now have the bool value of E[0] on the stack. + LabelTy LabelTrue = this->getLabel(); + if (!this->jumpTrue(LabelTrue)) + return false; + + if (!this->emitConstUint8(1, CE)) + return false; + if (!this->emitArrayElemPtrPopUint8(CE)) + return false; + if (!this->emitLoadPop(*ElemT, CE)) + return false; + if (!this->emitCast(*ElemT, PT_Bool, CE)) + return false; + // Leave the boolean value of E[1] on the stack. + LabelTy EndLabel = this->getLabel(); + this->jump(EndLabel); + + this->emitLabel(LabelTrue); + if (!this->emitPopPtr(CE)) + return false; + if (!this->emitConstBool(true, CE)) + return false; + + this->fallthrough(EndLabel); + this->emitLabel(EndLabel); + + return true; + } + case CK_ToVoid: return discard(SubExpr); @@ -1673,7 +1719,8 @@ template bool ByteCodeExprGen::visit(const Expr *E) { return this->discard(E); // Create local variable to hold the return value. - if (!E->isGLValue() && !classify(E->getType())) { + if (!E->isGLValue() && !E->getType()->isAnyComplexType() && + !classify(E->getType())) { std::optional LocalIndex = allocateLocal(E, /*IsExtended=*/true); if (!LocalIndex) return false; @@ -1859,6 +1906,9 @@ bool ByteCodeExprGen::dereference( return Indirect(*T); } + if (LV->getType()->isAnyComplexType()) + return visit(LV); + return false; } diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index bc1d5d11a1151..1c4739544454a 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -285,6 +285,14 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, } bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E); + std::optional classifyComplexElementType(QualType T) const { + assert(T->isAnyComplexType()); + + QualType ElemType = T->getAs()->getElementType(); + + return this->classify(ElemType); + } + bool emitRecordDestruction(const Descriptor *Desc); unsigned collectBaseOffset(const RecordType *BaseType, const RecordType *DerivedType); diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index ba9fcd39fdd77..dbdbc2f7356e6 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -49,8 +49,21 @@ static_assert(__real(I3) == 15, ""); static_assert(__imag(I3) == 15, ""); #endif - - - /// FIXME: This should work in the new interpreter as well. // constexpr _Complex _BitInt(8) A = 0;// = {4}; + +namespace CastToBool { + constexpr _Complex int F = {0, 1}; + static_assert(F, ""); + constexpr _Complex int F2 = {1, 0}; + static_assert(F2, ""); + constexpr _Complex int F3 = {0, 0}; + static_assert(!F3, ""); + + constexpr _Complex unsigned char F4 = {0, 1}; + static_assert(F4, ""); + constexpr _Complex unsigned char F5 = {1, 0}; + static_assert(F5, ""); + constexpr _Complex unsigned char F6 = {0, 0}; + static_assert(!F6, ""); +}