Skip to content

Commit

Permalink
[clang][Interp] Handle casts between complex types (#79269)
Browse files Browse the repository at this point in the history
Just handle this like two primtive casts.
  • Loading branch information
tbaederr committed Jan 31, 2024
1 parent 5d7d89d commit 32c0048
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
57 changes: 57 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,63 @@ bool ByteCodeExprGen<Emitter>::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<unsigned> 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<unsigned> 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<ComplexType>()->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);

Expand Down
10 changes: 8 additions & 2 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<ComplexType>())
return CT->getElementType();
}
return getFieldDesc()->getType();
}

Expand Down
19 changes: 17 additions & 2 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, "");

Expand Down

0 comments on commit 32c0048

Please sign in to comment.