Skip to content

Commit 32c0048

Browse files
authored
[clang][Interp] Handle casts between complex types (#79269)
Just handle this like two primtive casts.
1 parent 5d7d89d commit 32c0048

File tree

3 files changed

+82
-4
lines changed

3 files changed

+82
-4
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,63 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
311311
return this->emitInitElem(T, 1, SubExpr);
312312
}
313313

314+
case CK_IntegralComplexCast:
315+
case CK_FloatingComplexCast:
316+
case CK_IntegralComplexToFloatingComplex:
317+
case CK_FloatingComplexToIntegralComplex: {
318+
assert(CE->getType()->isAnyComplexType());
319+
assert(SubExpr->getType()->isAnyComplexType());
320+
if (DiscardResult)
321+
return this->discard(SubExpr);
322+
323+
if (!Initializing) {
324+
std::optional<unsigned> LocalIndex =
325+
allocateLocal(CE, /*IsExtended=*/true);
326+
if (!LocalIndex)
327+
return false;
328+
if (!this->emitGetPtrLocal(*LocalIndex, CE))
329+
return false;
330+
}
331+
332+
// Location for the SubExpr.
333+
// Since SubExpr is of complex type, visiting it results in a pointer
334+
// anyway, so we just create a temporary pointer variable.
335+
std::optional<unsigned> SubExprOffset = allocateLocalPrimitive(
336+
SubExpr, PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false);
337+
if (!SubExprOffset)
338+
return false;
339+
340+
if (!this->visit(SubExpr))
341+
return false;
342+
if (!this->emitSetLocal(PT_Ptr, *SubExprOffset, CE))
343+
return false;
344+
345+
PrimType SourceElemT = *classifyComplexElementType(SubExpr->getType());
346+
QualType DestElemType =
347+
CE->getType()->getAs<ComplexType>()->getElementType();
348+
PrimType DestElemT = classifyPrim(DestElemType);
349+
// Cast both elements individually.
350+
for (unsigned I = 0; I != 2; ++I) {
351+
if (!this->emitGetLocal(PT_Ptr, *SubExprOffset, CE))
352+
return false;
353+
if (!this->emitConstUint8(I, CE))
354+
return false;
355+
if (!this->emitArrayElemPtrPopUint8(CE))
356+
return false;
357+
if (!this->emitLoadPop(SourceElemT, CE))
358+
return false;
359+
360+
// Do the cast.
361+
if (!this->emitPrimCast(SourceElemT, DestElemT, DestElemType, CE))
362+
return false;
363+
364+
// Save the value.
365+
if (!this->emitInitElem(DestElemT, I, CE))
366+
return false;
367+
}
368+
return true;
369+
}
370+
314371
case CK_ToVoid:
315372
return discard(SubExpr);
316373

clang/lib/AST/Interp/Pointer.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,14 @@ class Pointer {
238238

239239
/// Returns the type of the innermost field.
240240
QualType getType() const {
241-
if (inPrimitiveArray() && Offset != Base)
242-
return getFieldDesc()->getType()->getAsArrayTypeUnsafe()->getElementType();
241+
if (inPrimitiveArray() && Offset != Base) {
242+
// Unfortunately, complex types are not array types in clang, but they are
243+
// for us.
244+
if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
245+
return AT->getElementType();
246+
if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>())
247+
return CT->getElementType();
248+
}
243249
return getFieldDesc()->getType();
244250
}
245251

clang/test/AST/Interp/complex.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,31 @@ static_assert(__real(12u) == 12u, "");
4747
static_assert(__imag(4.0) == 0.0, "");
4848
static_assert(__imag(13) == 0, "");
4949

50-
constexpr int ignoredCast() {
50+
51+
constexpr _Complex long L1 = D;
52+
static_assert(__real(L1) == 1.0, "");
53+
static_assert(__imag(L1) == 3.0, "");
54+
55+
constexpr _Complex short I4 = L1;
56+
static_assert(__real(I4) == 1, "");
57+
static_assert(__imag(I4) == 3, "");
58+
59+
constexpr _Complex float D3 = D;
60+
static_assert(__real(D3) == 1.0, "");
61+
static_assert(__imag(D3) == 3.0, "");
62+
63+
64+
constexpr int ignored() {
5165
I2;
5266
(int)I2;
5367
(float)I2;
5468
D1;
5569
(int)D1;
5670
(double)D1;
71+
(_Complex float)I2;
5772
return 0;
5873
}
59-
static_assert(ignoredCast() == 0, "");
74+
static_assert(ignored() == 0, "");
6075
static_assert((int)I1 == 1, "");
6176
static_assert((float)D == 1.0f, "");
6277

0 commit comments

Comments
 (0)