Skip to content

Commit 720f2f8

Browse files
committed
[clang][Interp] Handle complex values in visitBool()
In C++, we get a ComplexToBool cast, but we might not in C.
1 parent 17a1b8f commit 720f2f8

File tree

4 files changed

+82
-50
lines changed

4 files changed

+82
-50
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -241,57 +241,11 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
241241

242242
case CK_IntegralComplexToBoolean:
243243
case CK_FloatingComplexToBoolean: {
244-
PrimType ElemT = classifyComplexElementType(SubExpr->getType());
245-
// We emit the expression (__real(E) != 0 || __imag(E) != 0)
246-
// for us, that means (bool)E[0] || (bool)E[1]
244+
if (DiscardResult)
245+
return this->discard(SubExpr);
247246
if (!this->visit(SubExpr))
248247
return false;
249-
if (!this->emitConstUint8(0, CE))
250-
return false;
251-
if (!this->emitArrayElemPtrUint8(CE))
252-
return false;
253-
if (!this->emitLoadPop(ElemT, CE))
254-
return false;
255-
if (ElemT == PT_Float) {
256-
if (!this->emitCastFloatingIntegral(PT_Bool, CE))
257-
return false;
258-
} else {
259-
if (!this->emitCast(ElemT, PT_Bool, CE))
260-
return false;
261-
}
262-
263-
// We now have the bool value of E[0] on the stack.
264-
LabelTy LabelTrue = this->getLabel();
265-
if (!this->jumpTrue(LabelTrue))
266-
return false;
267-
268-
if (!this->emitConstUint8(1, CE))
269-
return false;
270-
if (!this->emitArrayElemPtrPopUint8(CE))
271-
return false;
272-
if (!this->emitLoadPop(ElemT, CE))
273-
return false;
274-
if (ElemT == PT_Float) {
275-
if (!this->emitCastFloatingIntegral(PT_Bool, CE))
276-
return false;
277-
} else {
278-
if (!this->emitCast(ElemT, PT_Bool, CE))
279-
return false;
280-
}
281-
// Leave the boolean value of E[1] on the stack.
282-
LabelTy EndLabel = this->getLabel();
283-
this->jump(EndLabel);
284-
285-
this->emitLabel(LabelTrue);
286-
if (!this->emitPopPtr(CE))
287-
return false;
288-
if (!this->emitConstBool(true, CE))
289-
return false;
290-
291-
this->fallthrough(EndLabel);
292-
this->emitLabel(EndLabel);
293-
294-
return true;
248+
return this->emitComplexBoolCast(SubExpr);
295249
}
296250

297251
case CK_IntegralComplexToReal:
@@ -2223,8 +2177,15 @@ bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) {
22232177
template <class Emitter>
22242178
bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
22252179
std::optional<PrimType> T = classify(E->getType());
2226-
if (!T)
2180+
if (!T) {
2181+
// Convert complex values to bool.
2182+
if (E->getType()->isAnyComplexType()) {
2183+
if (!this->visit(E))
2184+
return false;
2185+
return this->emitComplexBoolCast(E);
2186+
}
22272187
return false;
2188+
}
22282189

22292190
if (!this->visit(E))
22302191
return false;
@@ -3383,6 +3344,63 @@ bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) {
33833344
return true;
33843345
}
33853346

3347+
template <class Emitter>
3348+
bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
3349+
assert(!DiscardResult);
3350+
PrimType ElemT = classifyComplexElementType(E->getType());
3351+
// We emit the expression (__real(E) != 0 || __imag(E) != 0)
3352+
// for us, that means (bool)E[0] || (bool)E[1]
3353+
if (!this->emitConstUint8(0, E))
3354+
return false;
3355+
if (!this->emitArrayElemPtrUint8(E))
3356+
return false;
3357+
if (!this->emitLoadPop(ElemT, E))
3358+
return false;
3359+
if (ElemT == PT_Float) {
3360+
if (!this->emitCastFloatingIntegral(PT_Bool, E))
3361+
return false;
3362+
} else {
3363+
if (!this->emitCast(ElemT, PT_Bool, E))
3364+
return false;
3365+
}
3366+
3367+
// We now have the bool value of E[0] on the stack.
3368+
LabelTy LabelTrue = this->getLabel();
3369+
if (!this->jumpTrue(LabelTrue))
3370+
return false;
3371+
3372+
if (!this->emitConstUint8(1, E))
3373+
return false;
3374+
if (!this->emitArrayElemPtrPopUint8(E))
3375+
return false;
3376+
if (!this->emitLoadPop(ElemT, E))
3377+
return false;
3378+
if (ElemT == PT_Float) {
3379+
if (!this->emitCastFloatingIntegral(PT_Bool, E))
3380+
return false;
3381+
} else {
3382+
if (!this->emitCast(ElemT, PT_Bool, E))
3383+
return false;
3384+
}
3385+
// Leave the boolean value of E[1] on the stack.
3386+
LabelTy EndLabel = this->getLabel();
3387+
this->jump(EndLabel);
3388+
3389+
this->emitLabel(LabelTrue);
3390+
if (!this->emitPopPtr(E))
3391+
return false;
3392+
if (!this->emitConstBool(true, E))
3393+
return false;
3394+
3395+
this->fallthrough(EndLabel);
3396+
this->emitLabel(EndLabel);
3397+
3398+
return true;
3399+
}
3400+
3401+
/// When calling this, we have a pointer of the local-to-destroy
3402+
/// on the stack.
3403+
/// Emit destruction of record types (or arrays of record types).
33863404
template <class Emitter>
33873405
bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Record *R) {
33883406
assert(R);

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
289289
}
290290

291291
bool emitComplexReal(const Expr *SubExpr);
292+
bool emitComplexBoolCast(const Expr *E);
292293

293294
bool emitRecordDestruction(const Record *R);
294295
bool emitDestruction(const Descriptor *Desc);

clang/test/AST/Interp/c.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,14 @@ void bar_0(void) {
150150
*(int *)(&S.a) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
151151
*(int *)(&S.b) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
152152
}
153+
154+
/// Complex-to-bool casts.
155+
const int A = ((_Complex double)1.0 ? 21 : 1);
156+
_Static_assert(A == 21, ""); // pedantic-ref-warning {{GNU extension}} \
157+
// pedantic-expected-warning {{GNU extension}}
158+
const int CTI1 = ((_Complex double){0.0, 1.0});
159+
_Static_assert(CTI1 == 0, "");
160+
const _Bool CTB2 = (_Bool)(_Complex double){0.0, 1.0};
161+
_Static_assert(CTB2, "");
162+
const _Bool CTB3 = (_Complex double){0.0, 1.0};
163+
_Static_assert(CTB3, "");

clang/test/AST/Interp/complex.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ constexpr int ignored() {
7777
(int)D1;
7878
(double)D1;
7979
(_Complex float)I2;
80+
(bool)D1;
81+
(bool)I2;
8082
return 0;
8183
}
8284
static_assert(ignored() == 0, "");

0 commit comments

Comments
 (0)