[clang] [clang][Interp] Handle complex values in visitBool() (PR #79452)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 12 23:45:20 PST 2024


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/79452

>From 9234c4224e02e5170d81aeb5fb2bfa9fe7a26eb1 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 | 115 +++++++++++++----------
 clang/lib/AST/Interp/ByteCodeExprGen.h   |   1 +
 clang/test/AST/Interp/c.c                |   4 +
 clang/test/AST/Interp/complex.cpp        |   2 +
 4 files changed, 72 insertions(+), 50 deletions(-)

diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index ba6c1d5f5c9470..eaa6d47f601bcc 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:
@@ -2120,8 +2074,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;
@@ -3249,6 +3210,60 @@ 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).
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index ae216f56713959..622a55a5a06041 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -285,6 +285,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   }
 
   bool emitComplexReal(const Expr *SubExpr);
+  bool emitComplexBoolCast(const Expr *E);
 
   bool emitRecordDestruction(const Descriptor *Desc);
   unsigned collectBaseOffset(const RecordType *BaseType,
diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 85c195d33a96d7..ba5c0678dfc39b 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -125,3 +125,7 @@ struct XY { int before; struct XX xx, *xp; float* after; } xy[] = {
   0,              // all-warning {{initializer overrides prior initialization of this subobject}}
   &xy[2].xx.a, &xy[2].xx, &global_float
 };
+
+const int A =  ((_Complex double)1.0 ? 21 : 1);
+_Static_assert(A == 21, ""); // 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