[clang] [clang][Interp] Handle complex values in visitBool() (PR #79452)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 19 21:00:34 PST 2024
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/79452
>From c1a7132cb9cf1773358c70a750af3b66213990d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 25 Jan 2024 15:20:52 +0100
Subject: [PATCH] [clang][Interp] Handle complex values in visitBool()
In C++, we get a ComplexToBool cast, but we might not in C.
---
clang/lib/AST/Interp/ByteCodeExprGen.cpp | 118 +++++++++++++----------
clang/lib/AST/Interp/ByteCodeExprGen.h | 1 +
clang/test/AST/Interp/c.c | 21 ++++
clang/test/AST/Interp/complex.cpp | 2 +
4 files changed, 92 insertions(+), 50 deletions(-)
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 2fdc6f4f32bed9..d4b285941d46d1 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -241,57 +241,11 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_IntegralComplexToBoolean:
case CK_FloatingComplexToBoolean: {
- PrimType ElemT = classifyComplexElementType(SubExpr->getType());
- // We emit the expression (__real(E) != 0 || __imag(E) != 0)
- // for us, that means (bool)E[0] || (bool)E[1]
+ if (DiscardResult)
+ return this->discard(SubExpr);
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 (ElemT == PT_Float) {
- if (!this->emitCastFloatingIntegral(PT_Bool, CE))
- return false;
- } else {
- 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 (ElemT == PT_Float) {
- if (!this->emitCastFloatingIntegral(PT_Bool, CE))
- return false;
- } else {
- 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;
+ return this->emitComplexBoolCast(SubExpr);
}
case CK_IntegralComplexToReal:
@@ -2223,8 +2177,15 @@ bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
std::optional<PrimType> T = classify(E->getType());
- if (!T)
+ if (!T) {
+ // Convert complex values to bool.
+ if (E->getType()->isAnyComplexType()) {
+ if (!this->visit(E))
+ return false;
+ return this->emitComplexBoolCast(E);
+ }
return false;
+ }
if (!this->visit(E))
return false;
@@ -3383,6 +3344,63 @@ bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) {
return true;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
+ assert(!DiscardResult);
+ PrimType ElemT = classifyComplexElementType(E->getType());
+ // We emit the expression (__real(E) != 0 || __imag(E) != 0)
+ // for us, that means (bool)E[0] || (bool)E[1]
+ if (!this->emitConstUint8(0, E))
+ return false;
+ if (!this->emitArrayElemPtrUint8(E))
+ return false;
+ if (!this->emitLoadPop(ElemT, E))
+ return false;
+ if (ElemT == PT_Float) {
+ if (!this->emitCastFloatingIntegral(PT_Bool, E))
+ return false;
+ } else {
+ if (!this->emitCast(ElemT, PT_Bool, E))
+ 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, E))
+ return false;
+ if (!this->emitArrayElemPtrPopUint8(E))
+ return false;
+ if (!this->emitLoadPop(ElemT, E))
+ return false;
+ if (ElemT == PT_Float) {
+ if (!this->emitCastFloatingIntegral(PT_Bool, E))
+ return false;
+ } else {
+ if (!this->emitCast(ElemT, PT_Bool, E))
+ 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(E))
+ return false;
+ if (!this->emitConstBool(true, E))
+ return false;
+
+ this->fallthrough(EndLabel);
+ this->emitLabel(EndLabel);
+
+ return true;
+}
+
+/// When calling this, we have a pointer of the local-to-destroy
+/// on the stack.
+/// Emit destruction of record types (or arrays of record types).
template <class Emitter>
bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Record *R) {
assert(R);
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 3ede86a6979eea..4c88e33b3ece47 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -289,6 +289,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
}
bool emitComplexReal(const Expr *SubExpr);
+ bool emitComplexBoolCast(const Expr *E);
bool emitRecordDestruction(const Record *R);
bool emitDestruction(const Descriptor *Desc);
diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index fe540dc83918fa..168b56988d065f 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -150,3 +150,24 @@ void bar_0(void) {
*(int *)(&S.a) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
*(int *)(&S.b) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
}
+
+/// Complex-to-bool casts.
+const int A = ((_Complex double)1.0 ? 21 : 1);
+_Static_assert(A == 21, ""); // pedantic-ref-warning {{GNU extension}} \
+ // pedantic-expected-warning {{GNU extension}}
+
+const int CTI1 = ((_Complex double){0.0, 1.0}); // pedantic-ref-warning {{extension}} \
+ // pedantic-expected-warning {{extension}}
+_Static_assert(CTI1 == 0, ""); // pedantic-ref-warning {{GNU extension}} \
+ // pedantic-expected-warning {{GNU extension}}
+
+const _Bool CTB2 = (_Bool)(_Complex double){0.0, 1.0}; // pedantic-ref-warning {{extension}} \
+ // pedantic-expected-warning {{extension}}
+_Static_assert(CTB2, ""); // pedantic-ref-warning {{GNU extension}} \
+ // pedantic-expected-warning {{GNU extension}}
+
+const _Bool CTB3 = (_Complex double){0.0, 1.0}; // pedantic-ref-warning {{extension}} \
+ // pedantic-expected-warning {{extension}}
+_Static_assert(CTB3, ""); // pedantic-ref-warning {{GNU extension}} \
+ // pedantic-expected-warning {{GNU extension}}
+
diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp
index 9fdaabd9081d56..612a94b31171b9 100644
--- a/clang/test/AST/Interp/complex.cpp
+++ b/clang/test/AST/Interp/complex.cpp
@@ -77,6 +77,8 @@ constexpr int ignored() {
(int)D1;
(double)D1;
(_Complex float)I2;
+ (bool)D1;
+ (bool)I2;
return 0;
}
static_assert(ignored() == 0, "");
More information about the cfe-commits
mailing list